Spring Boot自动注入的原理分析

前言

我们经常会被问到这么一个问题:SpringBoot" title="SpringBoot">SpringBoot相对于spring有哪些优势呢?其中有一条答案就是SpringBoot自动注入。那么自动注入的原理是什么呢?

我们进行如下分析。

1:首先我们分析项目的启动类时,发现都会加上@SpringBootApplication这个注解,我们分析这个继续进入这个注解会发现,它是由多个注解组成的,如下

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan(excludeFilters = {

@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),

@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

public @interface SpringBootApplication {

2:服务启动会扫描 org.springframework.boot.autoconfigure下的 META-INF/spring.factories 这个文件,这个文件中保存着springboot 启动时默认会自动注入的类,部分如下

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\

org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\

org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\

org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\

org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\

org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\

org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\

org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\

org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\

org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\

org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\

org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\

org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\

org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\

org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\

org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\

org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\

org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\

org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\

org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\

org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\

org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\

org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\

org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\

org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\

org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\

org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\

org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\

org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\

org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\

org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\

org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\

org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\

org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\

org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\

org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\

org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\

org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\

org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\

org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\

org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\

org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\

org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\

org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

3:你是不是在其中发现了自己常用的redis,mysql等相关的类?没错,springboot会尝试加载这些类,我们以 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration 这个类为例,进去看一下它的源码,部分示例如下

@Configuration

@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })

@EnableConfigurationProperties(RedisProperties.class)

public class RedisAutoConfiguration {

/**

* Redis connection configuration.

*/

@Configuration

@ConditionalOnClass(GenericObjectPool.class)

protected static class RedisConnectionConfiguration {

private final RedisProperties properties;

private final RedisSentinelConfiguration sentinelConfiguration;

private final RedisClusterConfiguration clusterConfiguration;

public RedisConnectionConfiguration(RedisProperties properties,

ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,

ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {

this.properties = properties;

this.sentinelConfiguration = sentinelConfiguration.getIfAvailable();

this.clusterConfiguration = clusterConfiguration.getIfAvailable();

}

@Bean

@ConditionalOnMissingBean(RedisConnectionFactory.class)

public JedisConnectionFactory redisConnectionFactory()

throws UnknownHostException {

return applyProperties(createJedisConnectionFactory());

}

我们能看到这个类上加了这个注解 @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }) 意思就是如果你的classpath中没有这些类的话,那么这个类就不能被加载,那么这些被依赖的类在哪出现呢?没错,就在我们在pom.xml中引入的依赖所对应的包里。

看到这里你因该就明白了,META-INF/spring.factories 文件中被列出来的那些类都会被springboot去尝试加载,但是有些模块我们没引入相关的依赖,那么这个类就会加载失败。即这个模块没有被成功加载。

4:我们通过上面的redis的自动加载类时,看到上面还有个 @EnableConfigurationProperties(RedisProperties.class) 注解,这个注解来注入关于redis的配置信息,这个信息都在 RedisProperties.class 中保存,我们看下 RedisProperties的源码

@ConfigurationProperties(prefix = "spring.redis")

public class RedisProperties {

/**

* Database index used by the connection factory.

*/

private int database = 0;

/**

* Redis url, which will overrule host, port and password if set.

*/

private String url;

/**

* Redis server host.

*/

private String host = "localhost";

/**

* Login password of the redis server.

*/

private String password;

/**

* Redis server port.

*/

private int port = 6379;

/**

* Enable SSL.

*/

private boolean ssl;

/**

* Connection timeout in milliseconds.

*/

private int timeout;

private Pool pool;

private Sentinel sentinel;

private Cluster cluster;

public int getDatabase() {

return this.database;

}

public void setDatabase(int database) {

this.database = database;

}

public String getUrl() {

return this.url;

}

public void setUrl(String url) {

this.url = url;

}

public String getHost() {

return this.host;

}

public void setHost(String host) {

this.host = host;

}

public String getPassword() {

return this.password;

}

public void setPassword(String password) {

this.password = password;

}

public int getPort() {

return this.port;

}

public void setPort(int port) {

this.port = port;

}

public boolean isSsl() {

return this.ssl;

}

public void setSsl(boolean ssl) {

this.ssl = ssl;

}

public void setTimeout(int timeout) {

this.timeout = timeout;

}

public int getTimeout() {

return this.timeout;

}

public Sentinel getSentinel() {

return this.sentinel;

}

public void setSentinel(Sentinel sentinel) {

this.sentinel = sentinel;

}

public Pool getPool() {

return this.pool;

}

public void setPool(Pool pool) {

this.pool = pool;

}

public Cluster getCluster() {

return this.cluster;

}

public void setCluster(Cluster cluster) {

this.cluster = cluster;

}

/**

* Pool properties.

*/

public static class Pool {

/**

* Max number of "idle" connections in the pool. Use a negative value to indicate

* an unlimited number of idle connections.

*/

private int maxIdle = 8;

/**

* Target for the minimum number of idle connections to maintain in the pool. This

* setting only has an effect if it is positive.

*/

private int minIdle = 0;

/**

* Max number of connections that can be allocated by the pool at a given time.

* Use a negative value for no limit.

*/

private int maxActive = 8;

/**

* Maximum amount of time (in milliseconds) a connection allocation should block

* before throwing an exception when the pool is exhausted. Use a negative value

* to block indefinitely.

*/

private int maxWait = -1;

public int getMaxIdle() {

return this.maxIdle;

}

public void setMaxIdle(int maxIdle) {

this.maxIdle = maxIdle;

}

public int getMinIdle() {

return this.minIdle;

}

public void setMinIdle(int minIdle) {

this.minIdle = minIdle;

}

public int getMaxActive() {

return this.maxActive;

}

public void setMaxActive(int maxActive) {

this.maxActive = maxActive;

}

public int getMaxWait() {

return this.maxWait;

}

public void setMaxWait(int maxWait) {

this.maxWait = maxWait;

}

}

/**

* Cluster properties.

*/

public static class Cluster {

/**

* Comma-separated list of "host:port" pairs to bootstrap from. This represents an

* "initial" list of cluster nodes and is required to have at least one entry.

*/

private List<String> nodes;

/**

* Maximum number of redirects to follow when executing commands across the

* cluster.

*/

private Integer maxRedirects;

public List<String> getNodes() {

return this.nodes;

}

public void setNodes(List<String> nodes) {

this.nodes = nodes;

}

public Integer getMaxRedirects() {

return this.maxRedirects;

}

public void setMaxRedirects(Integer maxRedirects) {

this.maxRedirects = maxRedirects;

}

}

/**

* Redis sentinel properties.

*/

public static class Sentinel {

/**

* Name of Redis server.

*/

private String master;

/**

* Comma-separated list of host:port pairs.

*/

private String nodes;

public String getMaster() {

return this.master;

}

public void setMaster(String master) {

this.master = master;

}

public String getNodes() {

return this.nodes;

}

public void setNodes(String nodes) {

this.nodes = nodes;

}

}

}

发现里面的配置项基本都是有默认值的,通过上面的注解可以明白,如果配置文件中存在 spring.redis 开头的配置项,则使用配置文件中的,如果没有的话则使用文件中默认写死的配置。你是不是想到了springboot的另外一个优势:约定大于配置。

这里我们大概了解了SpringBoot自动配置的原理和流程,里面的那些细节我们不在分析。同理,对于那些第三方或者我们自己写的starter,springboot启动的时候会扫描starter的jar包下 META-INF/spring.factories 这个文件,解析内容并加载里面对用的类。

由此,我们总结出以下几点

  1:SpringBoot的自动配置是如何实现的

  2:有关的那些注解,如@EnableAutoConfiguration, @ConditionalOnClass, @Configuration等也是SpringBoot的核心注解,也值得我们了解其用法和原理。

总结

以上是 Spring Boot自动注入的原理分析 的全部内容, 来源链接: utcz.com/z/312359.html

回到顶部