首页 > 编程 > Java > 正文

Spring Boot自动注入的原理分析

2019-11-26 08:27:28
字体:
来源:转载
供稿:网友

前言

我们经常会被问到这么一个问题: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 Configureorg.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的核心注解,也值得我们了解其用法和原理。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对武林网的支持。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表