溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring Boot自動(dòng)注入的原理分析

發(fā)布時(shí)間:2020-09-08 17:09:34 來(lái)源:腳本之家 閱讀:205 作者:李斯特王 欄目:編程語(yǔ)言

前言

我們經(jīng)常會(huì)被問(wèn)到這么一個(gè)問(wèn)題:SpringBoot相對(duì)于spring有哪些優(yōu)勢(shì)呢?其中有一條答案就是SpringBoot自動(dòng)注入。那么自動(dòng)注入的原理是什么呢?

我們進(jìn)行如下分析。

1:首先我們分析項(xiàng)目的啟動(dòng)類時(shí),發(fā)現(xiàn)都會(huì)加上@SpringBootApplication這個(gè)注解,我們分析這個(gè)繼續(xù)進(jìn)入這個(gè)注解會(huì)發(fā)現(xiàn),它是由多個(gè)注解組成的,如下

@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:服務(wù)啟動(dòng)會(huì)掃描 org.springframework.boot.autoconfigure下的 META-INF/spring.factories 這個(gè)文件,這個(gè)文件中保存著springboot 啟動(dòng)時(shí)默認(rèn)會(huì)自動(dòng)注入的類,部分如下

# 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.h3.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.oauth3.OAuth3AutoConfiguration,\
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:你是不是在其中發(fā)現(xiàn)了自己常用的redis,mysql等相關(guān)的類?沒(méi)錯(cuò),springboot會(huì)嘗試加載這些類,我們以 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration 這個(gè)類為例,進(jìn)去看一下它的源碼,部分示例如下

@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());
  }

我們能看到這個(gè)類上加了這個(gè)注解 @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }) 意思就是如果你的classpath中沒(méi)有這些類的話,那么這個(gè)類就不能被加載,那么這些被依賴的類在哪出現(xiàn)呢?沒(méi)錯(cuò),就在我們?cè)趐om.xml中引入的依賴所對(duì)應(yīng)的包里。

看到這里你因該就明白了,META-INF/spring.factories 文件中被列出來(lái)的那些類都會(huì)被springboot去嘗試加載,但是有些模塊我們沒(méi)引入相關(guān)的依賴,那么這個(gè)類就會(huì)加載失敗。即這個(gè)模塊沒(méi)有被成功加載。

4:我們通過(guò)上面的redis的自動(dòng)加載類時(shí),看到上面還有個(gè) @EnableConfigurationProperties(RedisProperties.class) 注解,這個(gè)注解來(lái)注入關(guān)于redis的配置信息,這個(gè)信息都在 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;
    }

  }

}

發(fā)現(xiàn)里面的配置項(xiàng)基本都是有默認(rèn)值的,通過(guò)上面的注解可以明白,如果配置文件中存在 spring.redis 開(kāi)頭的配置項(xiàng),則使用配置文件中的,如果沒(méi)有的話則使用文件中默認(rèn)寫死的配置。你是不是想到了springboot的另外一個(gè)優(yōu)勢(shì):約定大于配置。

這里我們大概了解了SpringBoot自動(dòng)配置的原理和流程,里面的那些細(xì)節(jié)我們不在分析。同理,對(duì)于那些第三方或者我們自己寫的starter,springboot啟動(dòng)的時(shí)候會(huì)掃描starter的jar包下 META-INF/spring.factories 這個(gè)文件,解析內(nèi)容并加載里面對(duì)用的類。

由此,我們總結(jié)出以下幾點(diǎn)

  1:SpringBoot的自動(dòng)配置是如何實(shí)現(xiàn)的

  2:有關(guān)的那些注解,如@EnableAutoConfiguration, @ConditionalOnClass, @Configuration等也是SpringBoot的核心注解,也值得我們了解其用法和原理。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI