SpringBoot自動注入分析
我們經常會被問到這麼一個問題:SpringBoot相對於spring有哪些優勢呢?其中有一條答案就是SpringBoot自動注入。那麼自動注入的原理是什麼呢?我們進行如下分析。
1:首先我們分析專案的啟動類時,發現都會加上@SpringBootApplication這個註解,我們分析這個繼續進入這個註解會發現,它是由多個註解組成的,如下
1 @Target(ElementType.TYPE) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Inherited 5 @SpringBootConfiguration 6 @EnableAutoConfiguration 7 @ComponentScan(excludeFilters = { 8 @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), 9 @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) 10 public @interface SpringBootApplication {
2:服務啟動會掃描 org.springframework.boot.autoconfigure下的 META-INF/spring.factories 這個檔案,這個檔案中儲存著springboot 啟動時預設會自動注入的類,部分如下
1 # Auto Configure 2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 3 org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ 4 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ 5 org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ 6 org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ 7 org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ 8 org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ 9 org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ 10 org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ 11 org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ 12 org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ 13 org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ 14 org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ 15 org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ 16 org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ 17 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ 18 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ 19 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ 20 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ 21 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ 22 org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ 23 org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ 24 org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ 25 org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ 26 org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ 27 org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ 28 org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ 29 org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ 30 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ 31 org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\ 32 org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\ 33 org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ 34 org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\ 35 org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ 36 org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ 37 org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\ 38 org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\ 39 org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\ 40 org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\ 41 org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\ 42 org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\ 43 org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ 44 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ 45 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ 46 org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\ 47 org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\ 48 org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ 49 org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\ 50 org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ 51 org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\ 52 org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\ 53 org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\ 54 org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ 55 org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ 56 org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ 57 org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\ 58 org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\ 59 org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\ 60 org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ 61 org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ 62 org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ 63 org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\ 64 org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\ 65 org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\ 66 org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\ 67 org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ 68 org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ 69 org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ 70 org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ 71 org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\ 72 org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ 73 org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\ 74 org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\ 75 org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\ 76 org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ 77 org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ 78 org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\ 79 org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\ 80 org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\ 81 org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\ 82 org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ 83 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ 84 org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ 85 org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ 86 org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ 87 org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\ 88 org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ 89 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\ 90 org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\ 91 org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\ 92 org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ 93 org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ 94 org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\ 95 org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ 96 org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\ 97 org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\ 98 org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
3:你是不是在其中發現了自己常用的redis,mysql等相關的類?沒錯,springboot會嘗試載入這些類,我們以 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration 這個類為例,進去看一下它的原始碼,部分示例如下
1 @Configuration 2 @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }) 3 @EnableConfigurationProperties(RedisProperties.class) 4 public class RedisAutoConfiguration { 5 6 /** 7 * Redis connection configuration. 8 */ 9 @Configuration 10 @ConditionalOnClass(GenericObjectPool.class) 11 protected static class RedisConnectionConfiguration { 12 13 private final RedisProperties properties; 14 15 private final RedisSentinelConfiguration sentinelConfiguration; 16 17 private final RedisClusterConfiguration clusterConfiguration; 18 19 public RedisConnectionConfiguration(RedisProperties properties, 20 ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration, 21 ObjectProvider<RedisClusterConfiguration> clusterConfiguration) { 22 this.properties = properties; 23 this.sentinelConfiguration = sentinelConfiguration.getIfAvailable(); 24 this.clusterConfiguration = clusterConfiguration.getIfAvailable(); 25 } 26 27 @Bean 28 @ConditionalOnMissingBean(RedisConnectionFactory.class) 29 public JedisConnectionFactory redisConnectionFactory() 30 throws UnknownHostException { 31 return applyProperties(createJedisConnectionFactory()); 32 }
我們能看到這個類上加了這個註解 @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }) 意思就是如果你的classpath中沒有這些類的話,那麼這個類就不能被載入,那麼這些被依賴的類在哪出現呢?沒錯,就在我們在pom.xml中引入的依賴所對應的包裡。
看到這裡你因該就明白了,META-INF/spring.factories 檔案中被列出來的那些類都會被springboot去嘗試載入,但是有些模組我們沒引入相關的依賴,那麼這個類就會載入失敗。即這個模組沒有被成功載入。
4:我們通過上面的redis的自動載入類時,看到上面還有個 @EnableConfigurationProperties(RedisProperties.class) 註解,這個註解來注入關於redis的配置資訊,這個資訊都在 RedisProperties.class 中儲存,我們看下 RedisProperties的原始碼
1 @ConfigurationProperties(prefix = "spring.redis") 2 public class RedisProperties { 3 4 /** 5 * Database index used by the connection factory. 6 */ 7 private int database = 0; 8 9 /** 10 * Redis url, which will overrule host, port and password if set. 11 */ 12 private String url; 13 14 /** 15 * Redis server host. 16 */ 17 private String host = "localhost"; 18 19 /** 20 * Login password of the redis server. 21 */ 22 private String password; 23 24 /** 25 * Redis server port. 26 */ 27 private int port = 6379; 28 29 /** 30 * Enable SSL. 31 */ 32 private boolean ssl; 33 34 /** 35 * Connection timeout in milliseconds. 36 */ 37 private int timeout; 38 39 private Pool pool; 40 41 private Sentinel sentinel; 42 43 private Cluster cluster; 44 45 public int getDatabase() { 46 return this.database; 47 } 48 49 public void setDatabase(int database) { 50 this.database = database; 51 } 52 53 public String getUrl() { 54 return this.url; 55 } 56 57 public void setUrl(String url) { 58 this.url = url; 59 } 60 61 public String getHost() { 62 return this.host; 63 } 64 65 public void setHost(String host) { 66 this.host = host; 67 } 68 69 public String getPassword() { 70 return this.password; 71 } 72 73 public void setPassword(String password) { 74 this.password = password; 75 } 76 77 public int getPort() { 78 return this.port; 79 } 80 81 public void setPort(int port) { 82 this.port = port; 83 } 84 85 public boolean isSsl() { 86 return this.ssl; 87 } 88 89 public void setSsl(boolean ssl) { 90 this.ssl = ssl; 91 } 92 93 public void setTimeout(int timeout) { 94 this.timeout = timeout; 95 } 96 97 public int getTimeout() { 98 return this.timeout; 99 } 100 101 public Sentinel getSentinel() { 102 return this.sentinel; 103 } 104 105 public void setSentinel(Sentinel sentinel) { 106 this.sentinel = sentinel; 107 } 108 109 public Pool getPool() { 110 return this.pool; 111 } 112 113 public void setPool(Pool pool) { 114 this.pool = pool; 115 } 116 117 public Cluster getCluster() { 118 return this.cluster; 119 } 120 121 public void setCluster(Cluster cluster) { 122 this.cluster = cluster; 123 } 124 125 /** 126 * Pool properties. 127 */ 128 public static class Pool { 129 130 /** 131 * Max number of "idle" connections in the pool. Use a negative value to indicate 132 * an unlimited number of idle connections. 133 */ 134 private int maxIdle = 8; 135 136 /** 137 * Target for the minimum number of idle connections to maintain in the pool. This 138 * setting only has an effect if it is positive. 139 */ 140 private int minIdle = 0; 141 142 /** 143 * Max number of connections that can be allocated by the pool at a given time. 144 * Use a negative value for no limit. 145 */ 146 private int maxActive = 8; 147 148 /** 149 * Maximum amount of time (in milliseconds) a connection allocation should block 150 * before throwing an exception when the pool is exhausted. Use a negative value 151 * to block indefinitely. 152 */ 153 private int maxWait = -1; 154 155 public int getMaxIdle() { 156 return this.maxIdle; 157 } 158 159 public void setMaxIdle(int maxIdle) { 160 this.maxIdle = maxIdle; 161 } 162 163 public int getMinIdle() { 164 return this.minIdle; 165 } 166 167 public void setMinIdle(int minIdle) { 168 this.minIdle = minIdle; 169 } 170 171 public int getMaxActive() { 172 return this.maxActive; 173 } 174 175 public void setMaxActive(int maxActive) { 176 this.maxActive = maxActive; 177 } 178 179 public int getMaxWait() { 180 return this.maxWait; 181 } 182 183 public void setMaxWait(int maxWait) { 184 this.maxWait = maxWait; 185 } 186 187 } 188 189 /** 190 * Cluster properties. 191 */ 192 public static class Cluster { 193 194 /** 195 * Comma-separated list of "host:port" pairs to bootstrap from. This represents an 196 * "initial" list of cluster nodes and is required to have at least one entry. 197 */ 198 private List<String> nodes; 199 200 /** 201 * Maximum number of redirects to follow when executing commands across the 202 * cluster. 203 */ 204 private Integer maxRedirects; 205 206 public List<String> getNodes() { 207 return this.nodes; 208 } 209 210 public void setNodes(List<String> nodes) { 211 this.nodes = nodes; 212 } 213 214 public Integer getMaxRedirects() { 215 return this.maxRedirects; 216 } 217 218 public void setMaxRedirects(Integer maxRedirects) { 219 this.maxRedirects = maxRedirects; 220 } 221 222 } 223 224 /** 225 * Redis sentinel properties. 226 */ 227 public static class Sentinel { 228 229 /** 230 * Name of Redis server. 231 */ 232 private String master; 233 234 /** 235 * Comma-separated list of host:port pairs. 236 */ 237 private String nodes; 238 239 public String getMaster() { 240 return this.master; 241 } 242 243 public void setMaster(String master) { 244 this.master = master; 245 } 246 247 public String getNodes() { 248 return this.nodes; 249 } 250 251 public void setNodes(String nodes) { 252 this.nodes = nodes; 253 } 254 255 } 256 257 }View Code
發現裡面的配置項基本都是有預設值的,通過上面的註解可以明白,如果配置檔案中存在 spring.redis 開頭的配置項,則使用配置檔案中的,如果沒有的話則使用檔案中預設寫死的配置。你是不是想到了springboot的另外一個優勢:約定大於配置。
這裡我們大概瞭解了SpringBoot自動配置的原理和流程,裡面的那些細節我們不在分析。由此,我們總結出以下幾點
1:SpringBoot的自動配置是如何實現的
2:有關的那些註解,如@EnableAutoConfiguration, @ConditionalOnClass, @Configuration等也是SpringBoot的核心註解,也值得我們瞭解其用法和原理。