我们经常会被问到这么一个问题: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 {View Code
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.WebServicesAutoConfigurationView Code
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 }View Code
我们能看到这个类上加了这个注解 @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的核心注解,也值得我们了解其用法和原理。