11、【网摘】Spring Boot自动配置原理

11、【网摘】Spring Boot自动配置原理

1、前言

我们知道,Spring Boot 项目创建完成后,即使不进行任何的配置,也能够顺利地运行,这都要归功于 Spring Boot 的自动化配置。

Spring Boot 默认使用 application.properties 或 application.yml 作为其全局配置文件,我们可以在该配置文件中对各种自动配置属性(server.port、logging.level.* 、spring.config.active.no-profile 等等)进行修改,并使之生效,那么您有没有想过这些属性是否有据可依呢?答案是肯定的。

Spring Boo小白学搭建点我wcqh.cnt 官方文档:常见应用属性中对所有的配置属性都进行了列举和解释,我们可以根据官方文档对 Spring Boot 进行配置,但 Spring Boot 中的配置属性数量庞大,仅仅依靠官方文档进行配置也十分麻烦。我们只有了解了 Spring Boot 自动配置的原理,才能更加轻松熟练地对 Spirng Boot 进行配置。本节为你揭开 SpringBoot 自动配置的神秘面纱。

2、Spring Factories 机制

Spring Boot 的自动配置是基于 Spring Factories 机制实现的。

Spring Factories 机制是 Spring Boot 中的一种服务发现机制,这种扩小白学搭建点我wcqh.cn展机制与 Java SPI 机制十分相似。Spring Boot 会自动扫描所有 Jar 包类路径下 META-INF/spring.factories 文件,并读取其中的内容,进行实例化,这种机制也是 Spring Boot Starter 的基础。

1、spring.factories

spring.factories 文件本质上与 properties 文件相似,其中包含一组或多组键值对(key=vlaue),其中,key 的取值为接口的完全限定名;value 的取值为接口实现类的完全限定名,一个接口可以设置多个实现类,不同实现类之间使用“,”隔开,例如:

org.springframewor小白学搭建点我wcqh.cnk.boot.autoconfigure.AutoConfigurationImportFilter=org.springframework.boot.autoconfigure.condition.OnBeanCondition,org.springframework.boot.autoconfigure.condition.OnClassCondition,org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

注意:文件中配置的内容过长,为了阅读方便而手动换行时,为了防止内容丢失可以使用“\”。

3小白学搭建点我wcqh.cn、Spring Factories 实现原理

spring-core 包里定义了 SpringFactoriesLoader 类,这个类会扫描所有 Jar 包类路径下的 META-INF/spring.factories 文件,并获取指定接口的配置。在 SpringFactoriesLoader 类中定义了两个对外的方法,如下表。

以上两个方法的关键都是从指定的 ClassLoader 中获取 spring.factories 文件,并解析得到类名列表,具体代码如下。

loadFactories() 方法能够获取指定接口的实现类对象,具体代码如下。 publicstatic<T>List<T>load小白学搭建点我wcqh.cnFactories(Class<T> factoryType,@NullableClassLoader classLoader){Assert.notNull(factoryType,“factoryType must not be null”);ClassLoader classLoaderToUse = classLoader;if(classLoader ==null){ classLoaderToUse =SpringFactoriesLoader.class.getClassLoader();}// 调用loadFactoryNames获取接口的实现类List<String>factoryImple小白学搭建点我wcqh.cnmentationNames= loadFactoryNames(factoryType, classLoaderToUse);if(logger.isTraceEnabled()){ logger.trace(“Loaded [“+ factoryType.getName()+“] names: “+ factoryImplementationNames);}// 遍历 factoryNames 数组,创建实现类的对象List<T> result =newArrayList(factoryImplementationNames.size());Iterator var5 =factoryImplementat小白学搭建点我wcqh.cnionNames.iterator();//排序while(var5.hasNext()){String factoryImplementationName =(String)var5.next(); result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));}AnnotationAwareOrderComparator.sort(result);return result;}

loadFactoryNames() 方法能够根据接口获取其实现类类名的集合,具体代码如下。

publicstat小白学搭建点我wcqh.cnicList<String> loadFactoryNames(Class<?> factoryType,@NullableClassLoader classLoader){ClassLoader classLoaderToUse = classLoader;if(classLoader ==null){ classLoaderToUse =SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();//获取自动配置类return(List)loadSpringFactories(classL小白学搭建点我wcqh.cnoaderToUse).getOrDefault(factoryTypeName,Collections.emptyList());}

loadSpringFactories() 方法能够读取该项目中所有 Jar 包类路径下 META-INF/spring.factories 文件的配置内容,并以 Map 集合的形式返回,具体代码如下。

privatestaticMap<String,List<String>> loadSpringFactories(ClassLoader classLoader){Map<String,List<String>> result =(Map)cache.get(class小白学搭建点我wcqh.cnLoader);if(result !=null){return result;}else{HashMap result =newHashMap();try{//扫描所有 Jar 包类路径下的 META-INF/spring.factories 文件Enumeration urls = classLoader.getResources(“META-INF/spring.factories”);while(urls.hasMoreElements()){ URL url =(URL)urls.nextElement();UrlResource resource =newUrlResource(url);//将扫描到的小白学搭建点我wcqh.cn META-INF/spring.factories 文件中内容包装成 properties 对象Properties properties =PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()){Map.Entry<?,?> entry =(Map.Entry)var6.next();//提取 properties 对象中的 key 值String factoryTypeName =((String)entry.getKey())小白学搭建点我wcqh.cn.trim();//提取 proper 对象中的 value 值(多个类的完全限定名使用逗号连接的字符串)// 使用逗号为分隔符转换为数组,数组内每个元素都是配置类的完全限定名String[] factoryImplementationNames =StringUtils.commaDelimitedListToStringArray((String)entry.getValue());String[] var10 = factoryImplementationNames;int var11 = factoryImplementationNames.length;//遍历配置类数组,并将数组转换为 list 小白学搭建点我wcqh.cn集合for(int var12 =0; var12 < var11;++var12){String factoryImplementationName = var10[var12];((List)result.computeIfAbsent(factoryTypeName,(key)->{returnnewArrayList();})).add(factoryImplementationName.trim());}}}//将 propertise 对象的 key 与由配置类组成的 List 集合一一对应存入名为 result 的 Map 中 result.replaceAll((factoryType,impl小白学搭建点我wcqh.cnementations)->{return(List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(),Collections::unmodifiableList));}); cache.put(classLoader, result);//返回 resultreturn result;}catch(IOException var14){thrownewIllegalArgumentException(“Unable to load factories from lo小白学搭建点我wcqh.cncation [META-INF/spring.factories]”, var14);}}}

4、自动配置的加载

Spring Boot 自动化配置也是基于 Spring Factories 机制实现的,在 spring-boot-autoconfigure-xxx.jar 类路径下的 META-INF/spring.factories 中设置了 Spring Boot 自动配置的内容 ,如下。

Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.boot.a小白学搭建点我wcqh.cnutoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,org.springframework.boot.autoconfigure小白学搭建点我wcqh.cn.cache.CacheAutoConfiguration,org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,org.springframework.boot.autocon小白学搭建点我wcqh.cnfigure.context.MessageSourceAutoConfiguration,org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,or小白学搭建点我wcqh.cng.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,org.springframework.boo小白学搭建点我wcqh.cnt.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,org.springframework.boot.autoconfigure.data.couchbas小白学搭建点我wcqh.cne.CouchbaseReactiveRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,org.springframework.boot.autoconfigure.data.elasticsearch.Elastic小白学搭建点我wcqh.cnsearchRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,org.springframework.boot.autoconfigure.data.jdbc小白学搭建点我wcqh.cn.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小白学搭建点我wcqh.cn.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAu小白学搭建点我wcqh.cntoConfiguration,org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,org.springframework.b小白学搭建点我wcqh.cnoot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org小白学搭建点我wcqh.cn.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.Sprin小白学搭建点我wcqh.cngDataWebAutoConfiguration,org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,org.springframework.boot.autocon小白学搭建点我wcqh.cnfigure.groovy.template.GroovyTemplateAutoConfiguration,org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,org.springframework.boot.autoconfig小白学搭建点我wcqh.cnure.hazelcast.HazelcastAutoConfiguration,org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,org.springfra小白学搭建点我wcqh.cnmework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,org.springframew小白学搭建点我wcqh.cnork.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,org.springframework.小白学搭建点我wcqh.cnboot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,org.springframework.小白学搭建点我wcqh.cnboot.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.autoc小白学搭建点我wcqh.cnonfigure.jsonb.JsonbAutoConfiguration,org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,org.springframewor小白学搭建点我wcqh.cnk.boot.autoconfigure.ldap.LdapAutoConfiguration,org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,org.springframework.boo小白学搭建点我wcqh.cnt.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,org.springframework.小白学搭建点我wcqh.cnboot.autoconfigure.neo4j.Neo4jAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,org.springframework.boot.autoconfigur小白学搭建点我wcqh.cne.r2dbc.R2dbcTransactionManagerAutoConfiguration,org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,org.springf小白学搭建点我wcqh.cnramework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,org.springframework.boot.autoconfigure.security.servlet小白学搭建点我wcqh.cn.SecurityFilterAutoConfiguration,org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAuto小白学搭建点我wcqh.cnConfiguration,org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,org.springframework.boot.autoconfigure.security.oau小白学搭建点我wcqh.cnth2.client.servlet.OAuth2ClientAutoConfiguration,org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,org.springframework.boot.autocon小白学搭建点我wcqh.cnfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfigurat小白学搭建点我wcqh.cnion,org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,org.springframework.boot.autoconfigure.validation.ValidationAuto小白学搭建点我wcqh.cnConfiguration,org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,org.springframework.b小白学搭建点我wcqh.cnoot.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.c小白学搭建点我wcqh.cnlient.ClientHttpConnectorAutoConfiguration,org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAu小白学搭建点我wcqh.cntoConfiguration,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小白学搭建点我wcqh.cn.servlet.WebMvcAutoConfiguration,org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConf小白学搭建点我wcqh.cniguration,org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

以上配置中,value 取值是由多个 xxxAutoConfiguration (使用逗号分隔)组成,每个 xxxAutoConfiguration 都是一个自动配置类。Spring Boot 启动时,会利用 Spring-Facto小白学搭建点我wcqh.cnries 机制,将这些 xxxAutoConfiguration 实例化并作为组件加入到容器中,以实现 Spring Boot 的自动配置。

5、@SpringBootApplication 注解

所有 Spring Boot 项目的主启动程序类上都使用了一个 @SpringBootApplication

注解,该注解是 Spring Boot 中最重要的注解之一 ,也是 Spring Boot 实现自动化配置的关键。

@SpringBootApplication 是一个组合元注解,其主要包含两个注解:@SpringBootConfiguration@EnableAutoConfiguration,其中 @小白学搭建点我wcqh.cnEnableAutoConfiguration

注解是 SpringBoot 自动化配置的核心所在。

图1:@SpringBootApplication 注解

6、@EnableAutoConfiguration 注解

@EnableAutoConfiguration 注解用于开启 Spring Boot 的自动配置功能, 它使用 Spring 框架提供的 @Import

注解通过 AutoConfigurationImportSelector类(选择器)给容器中导入自动配置组件。

AutoConfigurationImportSelector 类

图2:@EnableAutoConfiguration 注解

7、Au小白学搭建点我wcqh.cntoConfigurationImportSelector 类

AutoConfigurationImportSelector 类实现了 DeferredImportSelector 接口,AutoConfigurationImportSelector 中还包含一个静态内部类 AutoConfigurationGroup,它实现了 DeferredImportSelector 接口的内部接口 Group(Spring 5 新增)。

AutoConfigurationImportSelector 类中包含 3 个方法,如下表。

AutoConfigurationImportSelector 内各方法执小白学搭建点我wcqh.cn行顺序如下。

getImportGroup() 方法process() 方法selectImports() 方法

下面我们将分别对以上 3 个方法及其调用过程进行介绍。

1、getImportGroup() 方法

AutoConfigurationImportSelector 类中 getImportGroup() 方法主要用于获取实现了 DeferredImportSelector.Group 接口的类,代码如下。

publicClass<?extendsGroup> getImportGroup(){//获取实现了 DeferredImportSelector.Gorup 接口的 AutoConfig小白学搭建点我wcqh.cnurationImportSelector.AutoConfigurationGroup 类returnAutoConfigurationImportSelector.AutoConfigurationGroup.class;}

2、process() 方法

静态内部类 AutoConfigurationGroup 中的核心方法是 process(),该方法通过调用 getAutoConfigurationEntry() 方法读取 spring.factories 文件中的内容,获得自动配置类的集合,代码如下 。

publicvoid process(AnnotationMetadataannotat小白学搭建点我wcqh.cnionMetadata,DeferredImportSelector deferredImportSelector){Assert.state(deferredImportSelector instanceofAutoConfigurationImportSelector,()->{returnString.format(“Only %s implementations are supported, got %s”,AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getN小白学搭建点我wcqh.cname());});//拿到 META-INF/spring.factories中的EnableAutoConfiguration,并做排除、过滤处理//AutoConfigurationEntry里有需要引入配置类和排除掉的配置类,最终只要返回需要配置的配置类AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry =((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotati小白学搭建点我wcqh.cnonMetadata);//加入缓存,List<AutoConfigurationEntry>类型this.autoConfigurationEntries.add(autoConfigurationEntry);Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();while(var4.hasNext()){String importClassName =(String)var4.next();//加入缓存,Map<String, AnnotationMetadata>类型this.entries.putIfAbse小白学搭建点我wcqh.cnnt(importClassName, annotationMetadata);}}

getAutoConfigurationEntry() 方法通过调用 getCandidateConfigurations() 方法来获取自动配置类的完全限定名,并在经过排除、过滤等处理后,将其缓存到成员变量中,具体代码如下。

protectedAutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata){if(!this.isEnabled(小白学搭建点我wcqh.cnannotationMetadata)){return EMPTY_ENTRY;}else{//获取注解元数据中的属性设置AnnotationAttributes attributes =this.getAttributes(annotationMetadata);//获取自动配置类List<String> configurations =this.getCandidateConfigurations(annotationMetadata, attributes);//删除list 集合中重复的配置类 configurations =this.removeDuplicates(configurations);小白学搭建点我wcqh.cn//获取飘出导入的配置类Set<String> exclusions =this.getExclusions(annotationMetadata, attributes);//检查是否还存在排除配置类this.checkExcludedClasses(configurations, exclusions);//删除排除的配置类 configurations.removeAll(exclusions);//获取过滤器,过滤配置类 configurations =this.getConfigurationClassFilter().filter(configurations);//出发自动化配置导入事件thi小白学搭建点我wcqh.cns.fireAutoConfigurationImportEvents(configurations, exclusions);returnnewAutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}

在 getCandidateConfigurations() 方法中,根据 Spring Factories 机制调用 SpringFactoriesLoader 的 loadFactoryNames() 方法,根据 EnableAutoConfiguration.class (自动配置小白学搭建点我wcqh.cn接口)获取其实现类(自动配置类)的类名的集合,如下图。

getCandidateConfigurations 方法

图3:getCandidateConfigurations 方法

3. selectImports() 方法

以上所有方法执行完成后,AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports() 会将 process() 方法处理后得到的自动配置类,进行过滤、排除,最后将所有自动配置类添加到容器中。

publicIterable<DeferredImportSelector.Group.Entry>select小白学搭建点我wcqh.cnImports(){if(this.autoConfigurationEntries.isEmpty()){returnCollections.emptyList();}else{//获取所有需要排除的配置类Set<String> allExclusions =(Set)this.autoConfigurationEntries.stream(). map(AutoConfigurationImportSelector.AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet小白学搭建点我wcqh.cn());//获取所有经过自动化配置过滤器的配置类Set<String> processedConfigurations =(Set)this.autoConfigurationEntries.stream().map(AutoConfigurationImportSelector.AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).collect(Collectors.toCollection(LinkedHashSet::new));//排除过滤后配置类中需要排除的类processedConfigurati小白学搭建点我wcqh.cnons.removeAll(allExclusions);return(Iterable)this.sortAutoConfigurations(processedConfigurations,this.getAutoConfigurationMetadata()).stream().map((importClassName)->{returnnewDeferredImportSelector.Group.Entry((AnnotationMetadata)this.entries.get(importClassName), importClassName);}).collect(Collect小白学搭建点我wcqh.cnors.toList());}}

8、自动配置的生效和修改

spring.factories 文件中的所有自动配置类(xxxAutoConfiguration),都是必须在一定的条件下才会作为组件添加到容器中,配置的内容才会生效。这些限制条件在 Spring Boot 中以 @Conditional

派生注解的形式体现,如下表。

下面我们以 ServletWebServerFactoryAutoConfiguration 为例,介绍 Spring Boot 自动配置是如何生效的。

1、ServletWebServerFactoryAutoConfiguration

ServletWebServerFacto小白学搭建点我wcqh.cnryAutoConfiguration 代码如下。

@Configuration(//表示这是一个配置类,与 xml 配置文件等价,也可以给容器中添加组件 proxyBeanMethods =false)@AutoConfigureOrder(-2147483648)@ConditionalOnClass({ServletRequest.class})//判断当前项目有没有 ServletRequest 这个类@ConditionalOnWebApplication(// 判断当前应用是否是 web 应用,如果是,当前配置类生效 type =Type.SERVLET)@EnableConfigurati小白学搭建点我wcqh.cnonProperties({ServerProperties.class})//启动指定类的属性配置(ConfigurationProperties)功能;将配置文件中对应的值和 ServerProperties 绑定起来;并把 ServerProperties 加入到ioc容器中@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,EmbeddedTomcat.class,EmbeddedJetty.class,EmbeddedUndertow.class})publicclas小白学搭建点我wcqh.cnsServletWebServerFactoryAutoConfiguration{publicServletWebServerFactoryAutoConfiguration(){}@Bean//给容器中添加一个组件,这个组件的某些值需要从properties中获取publicServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,ObjectProvider<WebListenerRegistrar> webListenerRegistrars){r小白学搭建点我wcqh.cneturnnewServletWebServerFactoryCustomizer(serverProperties,(List) webListenerRegistrars.orderedStream().collect(Collectors.toList()));}@Bean@ConditionalOnClass( name ={“org.apache.catalina.startup.Tomcat”})publicTomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProper小白学搭建点我wcqh.cnties serverProperties){returnnewTomcatServletWebServerFactoryCustomizer(serverProperties);}@Bean@ConditionalOnMissingFilterBean({ForwardedHeaderFilter.class})@ConditionalOnProperty( value ={“server.forward-headers-strategy”}, havingValue =“framework”)publicFilterRegistrationBean<ForwardedHeaderFilter>for小白学搭建点我wcqh.cnwardedHeaderFilter(){ForwardedHeaderFilter filter =newForwardedHeaderFilter();FilterRegistrationBean<ForwardedHeaderFilter> registration =newFilterRegistrationBean(filter,newServletRegistrationBean[0]); registration.setDispatcherTypes(DispatcherType.REQUEST,newDispatcherType[]{DispatcherType.ASYNC,Dispat小白学搭建点我wcqh.cncherType.ERROR}); registration.setOrder(-2147483648);return registration;}publicstaticclassBeanPostProcessorsRegistrarimplementsImportBeanDefinitionRegistrar,BeanFactoryAware{privateConfigurableListableBeanFactory beanFactory;publicBeanPostProcessorsRegistrar(){}publicvoid setBeanFactory(BeanFactorybean小白学搭建点我wcqh.cnFactory)throwsBeansException{if(beanFactory instanceofConfigurableListableBeanFactory){this.beanFactory =(ConfigurableListableBeanFactory) beanFactory;}}publicvoid registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry){if(this.beanFactory !=null){this.registerSyn小白学搭建点我wcqh.cntheticBeanIfMissing(registry,“webServerFactoryCustomizerBeanPostProcessor”,WebServerFactoryCustomizerBeanPostProcessor.class,WebServerFactoryCustomizerBeanPostProcessor::new);this.registerSyntheticBeanIfMissing(registry,“errorPageRegistrarBeanPostProcessor”,ErrorPageRegistrarBeanPostProcessor.class,小白学搭建点我wcqh.cnErrorPageRegistrarBeanPostProcessor::new);}}private<T>void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,String name,Class<T> beanClass,Supplier<T> instanceSupplier){if(ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass,true,false))){RootBeanDefinition beanDefinition =newRo小白学搭建点我wcqh.cnotBeanDefinition(beanClass, instanceSupplier); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name, beanDefinition);}}}}

该类使用了以下注解:

@Configuration:用于定义一个配置类,可用于替换 Spring 中的 xml 配置文件;@Bean:被 @Configuration 注解的类内部,可以包含有一个或多个被 @Bean注解的方法,用于构建一个 Bean,并添加到 Spring 容器中;该注解与 spring 配置文件中 等价,方法名与 小白学搭建点我wcqh.cn的 id 或 name 属性等价,方法返回值与 class 属性等价;

除了 @Configuration@Bean 注解外,该类还使用 5 个 @Conditional 衍生注解:

@ConditionalOnClass({ServletRequest.class}):判断当前项目是否存在 ServletRequest 这个类,若存在,则该配置类生效。@ConditionalOnWebApplication(type = Type.SERVLET):判断当前应用是否是 Web 应用,如果是的话,当前配置类生效。@ConditionalOnClass(name = {“org.apache.catali小白学搭建点我wcqh.cnna.startup.Tomcat”}):判断是否存在 Tomcat 类,若存在则该方法生效。@ConditionalOnMissingFilterBean({ForwardedHeaderFilter.class}):判断容器中是否有 ForwardedHeaderFilter 这个过滤器,若不存在则该方法生效。@ConditionalOnProperty(value = {“server.forward-headers-strategy”},havingValue = “framework”):判断配置文件中是否存在 server.forward-headers-strategy = fr小白学搭建点我wcqh.cnamework,若不存在则该方法生效。

2、ServerProperties

ServletWebServerFactoryAutoConfiguration 类还使用了一个 @EnableConfigurationProperties 注解,通过该注解导入了一个 ServerProperties 类,其部分源码如下。

@ConfigurationProperties( prefix =“server”, ignoreUnknownFields =true)publicclassServerProperties{privateInteger port;privateInetAddress address;@Nest小白学搭建点我wcqh.cnedConfigurationPropertyprivatefinalErrorProperties error =newErrorProperties();privateServerProperties.ForwardHeadersStrategy forwardHeadersStrategy;privateString serverHeader;privateDataSize maxHttpHeaderSize =DataSize.ofKilobytes(8L);privateShutdown shutdown;@NestedConfigurationPropertyprivateSsl ssl;@Nes小白学搭建点我wcqh.cntedConfigurationPropertyprivatefinalCompression compression;@NestedConfigurationPropertyprivatefinalHttp2 http2;privatefinalServerProperties.Servlet servlet;privatefinalServerProperties.Tomcat tomcat;privatefinalServerProperties.Jetty jetty;privatefinalServerProperties.Netty netty;privatefinalServerProper小白学搭建点我wcqh.cnties.Undertow undertow;publicServerProperties(){this.shutdown =Shutdown.IMMEDIATE;this.compression =newCompression();this.http2 =newHttp2();this.servlet =newServerProperties.Servlet();this.tomcat =newServerProperties.Tomcat();this.jetty =newServerProperties.Jetty();this.netty =newServerProperties.Netty();th小白学搭建点我wcqh.cnis.undertow =newServerProperties.Undertow();}….}

我们看到,ServletWebServerFactoryAutoConfiguration 使用了一个 @EnableConfigurationProperties 注解,而 ServerProperties 类上则使用了一个 @ConfigurationProperties 注解。这其实是 Spring Boot 自动配置机制中的通用用法。

Spring Boot 中为我们提供了大量的自动配置类 XxxAutoConfiguration 以及 XxxProperties,每个自动配置类 XxxAutoCo小白学搭建点我wcqh.cnnfiguration 都使用了@EnableConfigurationProperties 注解,而每个 XxxProperties 上都使用 @ConfigurationProperties 注解。

@ConfigurationProperties 注解的作用,是将这个类的所有属性与配置文件中相关的配置进行绑定,以便于获取或修改配置,但是 @ConfigurationProperties 功能是由容器提供的,被它注解的类必须是容器中的一个组件,否则该功能就无法使用。

@EnableConfigurationProperties 注解的作用正是将指定的类以组件的形式注入到 IOC 容器中,并开启其 @Conf小白学搭建点我wcqh.cnigurationProperties 功能。

因此,@ConfigurationProperties + @EnableConfigurationProperties 组合使用,便可以为 XxxProperties 类实现配置绑定功能。

自动配置类 XxxAutoConfiguration 负责使用 XxxProperties 中属性进行自动配置,而 XxxProperties 则负责将自动配置属性与配置文件的相关配置进行绑定,以便于用户通过配置文件修改默认的自动配置。

也就是说,真正“限制”我们可以在配置文件中配置哪些属性的类就是这些 XxxxProperties 类,它与配置文件中定义的 prefix小白学搭建点我wcqh.cn 关键字开头的一组属性是唯一对应的。

注意:XxxAutoConfiguration 与 XxxProperties 并不是一一对应的,大多数情况都是多对多的关系,即一个 XxxAutoConfiguration 可以同时使用多个 XxxProperties 中的属性,一个 XxxProperties 类中属性也可以被多个 XxxAutoConfiguration 使用。

加入

QQ群:722461036

微信群:一起督促、学习、练习、温习、复习 ~ ~ ~
作者最新博文
2021-03-10 21:42:47

© 版权声明
THE END
喜欢就支持一下吧
点赞131 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容