SpringBoot自动配置原理

1. 自动导入包的原理

我们都知道,SpringBoot会把主程序类所在包下的所有组件加入到容器中,这个是怎么实现的呢?

  1. 首先查看一下@SpringBootApplication这个注解

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
         @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    

    可以看到这个注解是由三个子注解构成的

    1. @SpringBootConfiguration

      @Configuration
      public @interface SpringBootConfiguration {}
      

      这个注解的核心就是一个Spring底层的@Configuration注解,表示被注解的是一个配置类

    2. @ComponentScan

      该注解就是用来扫描指定包下的用@Component注解的类的

    3. @EnableAutoConfiguration

      该注解才是实现自动导入包的核心!!!

      @AutoConfigurationPackage
      @Import(AutoConfigurationImportSelector.class)
      public @interface EnableAutoConfiguration {}
      
      • 关键是看这个注解 -- @AutoConfigurationPackage

        @Import(AutoConfigurationPackages.Registrar.class)
        public @interface AutoConfigurationPackage {}
        

        这个注解使用了@Import的高级用法,可以批量导入组件,我们点进Registrar看看

        static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        
            @Override
            public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
                register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
            }
        
            @Override
            public Set determineImports(AnnotationMetadata metadata) {
                return Collections.singleton(new PackageImports(metadata));
            }
        
        }
         

        register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));

        这句代码就是核心!new PackageImports(metadata).getPackageNames()这个的返回结果就是SpringBoot主程序类所在包的路径,比如这里我们把主程序类放在了com.plasticine.boot这个包下,那么这段代码返回的结果就是com.plasticine.boot,然后就可以把这个包下的组件都批量导入了!

      • @Import(AutoConfigurationImportSelector.class)

        重点是看AutoConfigurationImportSelector这个类里面是做了什么从而实现了自动装配,点进去后可以看到有一个方法selectImports

        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
        

        该方法的意思大概就是根据注解元信息获取到自动配置的入口,这个入口就是用@Configuration注解标记过的类构成的集合,然后从这些集合中得到所有的配置信息后转成字符串数组返回,后面就可以根据返回的字符串数组中的有哪些全类名去进行自动装配了

        所以核心就在于getAutoConfigurationEntry(annotationMetadata)这个方法,这个方法中有一步是获取所有要导入到容器中的配置类的,也就是

        List configurations = getCandidateConfigurations(annotationMetadata, attributes);
        
        configurations变量中的内容,即所有的自动装配类

        点进getCandidateConfigurations方法查看

        List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                        getBeanClassLoader());
        

        可以看到配置类是从Spring的工厂中加载来的,再点进loadFactoryNames这个方法查看

        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
        

        这个方法最终返回是通过调用loadSpringFactories这个方法,那么再点进这个方法看看

        package org.springframework.core.io.support;
        Enumeration urls = classLoader.getResources("META-INF/spring.factories");
        

        终于看到有这样一行和配置相关的了,Spring就是从这里去加载要使用的配置类的,我们可以找到springboot的这个包org.springframework.core.io.support,也就是spring-boot-autoconfigure-2.5.4.jar,在这个包的META-INF中就可以看到spring.factories这个文件,打开后看到有一行注释是Auto Configure

        # 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.context.ConfigurationPropertiesAutoConfiguration,\
        org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
        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.CassandraReactiveDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
        org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
        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.ElasticsearchRestClientAutoConfiguration,\
        org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
        org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
        org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
        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.http.HttpMessageConvertersAutoConfiguration,\
        org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
        org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
        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.jersey.JerseyAutoConfiguration,\
        org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
        org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
        org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
        org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
        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.mongo.embedded.EmbeddedMongoAutoConfiguration,\
        org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
        org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
        org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
        org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\
        org.springframework.boot.autoconfigure.netty.NettyAutoConfiguration,\
        org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
        org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
        org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
        org.springframework.boot.autoconfigure.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
        org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
        org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
        org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
        org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
        org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
        org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
        org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
        org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
        org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration,\
        org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
        org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
        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.client.RestTemplateAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
        org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
        org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
        org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
        org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
        org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
        org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
        

        正好就是这里面的131个配置类,虽然springboot把这么多配置类都加载进容器中了,但是项目中并不是每一个都用到了,所以springboot有一个按需开启的功能,启动springboot的时候会默认加载所有的自动配置类,但是只有我们用到了的配置项才会真正的自动装配到容器中,按需配置

        • 这句话什么意思呢?随便举一个例子吧

          就拿aop为例,如果项目中没有用到aop,那么虽然配置项中有aop这一项

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

          但是当我们点进去AopAutoConfiguration这个类看一看就会发现

          public class AopAutoConfiguration {
          
            @Configuration(proxyBeanMethods = false)
            @ConditionalOnClass(Advice.class)
            static class AspectJAutoProxyingConfiguration {
                  ...
              }
          

          这个类被@ConditionalOnClass注解了,也就是说,容器中有Advice这个类的时候,才会自动装配aop,而Advice就是import org.aspectj.weaver.Advice;,所以如果我们项目中没有在pom.xml中引入aspectj依赖的话,Advice这个类是无法导入的,那么aop的自动装配也就不会发生

      • 你可能感兴趣的:(SpringBoot自动配置原理)