我们经常会被问到这么一个问题: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 }
发现里面的配置项基本都是有默认值的,通过上面的注解可以明白,如果配置文件中存在 spring.redis 开头的配置项,则使用配置文件中的,如果没有的话则使用文件中默认写死的配置。你是不是想到了springboot的另外一个优势:约定大于配置。
这里我们大概了解了SpringBoot自动配置的原理和流程,里面的那些细节我们不在分析。同理,对于那些第三方或者我们自己写的starter,springboot启动的时候会扫描starter的jar包下 META-INF/spring.factories 这个文件,解析内容并加载里面对用的类。
由此,我们总结出以下几点
1:SpringBoot的自动配置是如何实现的
2:有关的那些注解,如@EnableAutoConfiguration, @ConditionalOnClass, @Configuration等也是SpringBoot的核心注解,也值得我们了解其用法和原理。