SpringBoot自动配置原理

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

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

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

SpringFactories机制

SpringBoot的自动配置是基于SpringFactories机制实现的。

SpringFactories机制是SpringBoot中的一种服务发现机制,这种扩展机制与JavaSPI机制十分相似。SpringBoot会自动扫描所有Jar包类路径下META-INF/spring.factories文件,并读取其中的内容,进行实例化,这种机制也是SpringBootStarter的基础。

spring.factories

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

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=org.springframework.boot.autoconfigure.condition.OnBeanCondition,org.springframework.boot.autoconfigure.condition.OnClassCondition,org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition1234复制代码类型:[java]

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

SpringFactories实现原理

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

返回值 方法 描述
<T> List<T>  loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) 静态方法;
根据接口获取其实现类的实例;
该方法返回的是实现类对象列表。
List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)  公共静态方法;
根据接口l获取其实现类的名称;
该方法返回的是实现类的类名的列表

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

public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
 Assert.notNull(factoryType, "'factoryType' must not be null");
 ClassLoader classLoaderToUse = classLoader; if (classLoader == null) {
  classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
 } // 调用loadFactoryNames获取接口的实现类
 List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse); if (logger.isTraceEnabled()) {
  logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
 } // 遍历 factoryNames 数组,创建实现类的对象
 List<T> result = new ArrayList(factoryImplementationNames.size());
 Iterator var5 = factoryImplementationNames.iterator(); //排序
 while(var5.hasNext()) {
  String factoryImplementationName = (String)var5.next();
  result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
 }
 AnnotationAwareOrderComparator.sort(result); return result;
}12345678910111213141516171819202122复制代码类型:[java]

loadFactories()方法能够获取指定接口的实现类对象,具体代码如下。

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
 ClassLoader classLoaderToUse = classLoader; if (classLoader == null) {
  classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
 }
 String factoryTypeName = factoryType.getName(); //获取自动配置类
 return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}123456789复制代码类型:[java]

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

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
 Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null) {  return result;
 } else {
  HashMap result = new HashMap(); try {  //扫描所有 Jar 包类路径下的 META-INF/spring.factories 文件
  Enumeration urls = classLoader.getResources("META-INF/spring.factories");  while(urls.hasMoreElements()) {
 URL url = (URL)urls.nextElement();
 UrlResource resource = new UrlResource(url); //将扫描到的 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()).trim();  //提取 proper 对象中的 value 值(多个类的完全限定名使用逗号连接的字符串)
  // 使用逗号为分隔符转换为数组,数组内每个元素都是配置类的完全限定名
  String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
  String[] var10 = factoryImplementationNames;  int var11 = factoryImplementationNames.length;  //遍历配置类数组,并将数组转换为 list 集合
  for(int var12 = 0; var12 < var11; ++var12) {
   String factoryImplementationName = var10[var12];
   ((List)result.computeIfAbsent(factoryTypeName, (key) -> {    return new ArrayList();
   })).add(factoryImplementationName.trim());
  }
 }
   }   //将 propertise 对象的 key 与由配置类组成的 List 集合一一对应存入名为 result 的 Map 中
   result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
   });
   cache.put(classLoader, result);   //返回 result
   return result;
  } catch (IOException var14) {   throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
  }
  }
}123456789101112131415161718192021222324252627282930313233343536373839404142434445复制代码类型:[java]

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

自动配置的加载

SpringBoot自动化配置也是基于SpringFactories机制实现的,在spring-boot-autoconfigure-xxx.jar类路径下的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.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.solr.SolrRepositoriesAutoConfiguration,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.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.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.WebServiceTemplateAutoConfiguration123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132复制代码类型:[java]

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

@SpringBootApplication注解

所有SpringBoot项目的主启动程序类上都使用了一个@SpringBootApplication注解,该注解是SpringBoot中最重要的注解之一,也是SpringBoot实现自动化配置的关键。

@SpringBootApplication是一个组合元注解,其主要包含两个注解:@SpringBootConfiguration和@EnableAutoConfiguration,其中@EnableAutoConfiguration注解是SpringBoot自动化配置的核心所在。

@EnableAutoConfiguration注解

@EnableAutoConfiguration注解用于开启SpringBoot的自动配置功能,它使用Spring框架提供的@Import注解通过AutoConfigurationImportSelector类(选择器)给容器中导入自动配置组件。

AutoConfigurationImportSelector类

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

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

返回值 方法声明 描述 内部类方法 内部类
Class<? extends Group> getImportGroup() 该方法获取实现了 Group 接口的类,并实例化
void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) 该方法用于引入自动配置的集合 AutoConfigurationGroup
Iterable<Entry> selectImports() 遍历自动配置类集合(Entry 类型的集合),并逐个解析集合中的配置类 AutoConfigurationGroup

AutoConfigurationImportSelector内各方法执行顺序如下。

1、getImportGroup()方法

2、process()方法

3、selectImports()方法

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

1.getImportGroup()方法

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

public Class<? extends Group> getImportGroup() {  //获取实现了 DeferredImportSelector.Gorup 接口的 AutoConfigurationImportSelector.AutoConfigurationGroup 类
  return AutoConfigurationImportSelector.AutoConfigurationGroup.class;
 }1234复制代码类型:[java]

2.process()方法

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

public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
 Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {  return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
 }); //拿到 META-INF/spring.factories中的EnableAutoConfiguration,并做排除、过滤处理
 //AutoConfigurationEntry里有需要引入配置类和排除掉的配置类,最终只要返回需要配置的配置类
 AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata); //加入缓存,List<AutoConfigurationEntry>类型
 this.autoConfigurationEntries.add(autoConfigurationEntry);
 Iterator var4 = autoConfigurationEntry.getConfigurations().iterator(); while(var4.hasNext()) {
  String importClassName = (String)var4.next();  //加入缓存,Map<String, AnnotationMetadata>类型
  this.entries.putIfAbsent(importClassName, annotationMetadata);
 }
}12345678910111213141516复制代码类型:[java]

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

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) {  return EMPTY_ENTRY;
 } else {  //获取注解元数据中的属性设置
  AnnotationAttributes attributes = this.getAttributes(annotationMetadata);  //获取自动配置类
  List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);  //删除list 集合中重复的配置类
  configurations = this.removeDuplicates(configurations);  //获取飘出导入的配置类
  Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);  //检查是否还存在排除配置类
  this.checkExcludedClasses(configurations, exclusions);  //删除排除的配置类
  configurations.removeAll(exclusions);  //获取过滤器,过滤配置类
  configurations = this.getConfigurationClassFilter().filter(configurations);  //出发自动化配置导入事件
  this.fireAutoConfigurationImportEvents(configurations, exclusions);  return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
 }
}1234567891011121314151617181920212223复制代码类型:[java]

在getCandidateConfigurations()方法中,根据SpringFactories机制调用SpringFactoriesLoader的loadFactoryNames()方法,根据EnableAutoConfiguration.class(自动配置接口)获取其实现类(自动配置类)的类名的集合,如下图。

3.process()方法

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

public Iterable<DeferredImportSelector.Group.Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) {  return Collections.emptyList();
 } else {  //获取所有需要排除的配置类
  Set<String> allExclusions = (Set)this.autoConfigurationEntries.stream().
 map(AutoConfigurationImportSelector.AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());  //获取所有经过自动化配置过滤器的配置类
  Set<String> processedConfigurations = (Set)this.autoConfigurationEntries.stream().map(AutoConfigurationImportSelector.
 AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).collect(Collectors.toCollection(LinkedHashSet::new));  //排除过滤后配置类中需要排除的类
  processedConfigurations.removeAll(allExclusions);  return (Iterable)this.sortAutoConfigurations(processedConfigurations, this.getAutoConfigurationMetadata()).stream().map((importClassName) -> {   return new DeferredImportSelector.Group.Entry((AnnotationMetadata)this.entries.get(importClassName), importClassName);
  }).collect(Collectors.toList());
 }
}123456789101112131415161718复制代码类型:[java]

自动配置的生效和修改

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

注解 生效条件
@ConditionalOnJava 应用使用指定的 Java 版本时生效
@ConditionalOnBean 容器中存在指定的  Bean 时生效
@ConditionalOnMissingBean  容器中不存在指定的 Bean 时生效
@ConditionalOnExpression 满足指定的 SpEL 表达式时生效
@ConditionalOnClass 存在指定的类时生效
@ConditionalOnMissingClass 不存在指定的类时生效
@ConditionalOnSingleCandidate  容器中只存在一个指定的 Bean 或这个 Bean 为首选 Bean 时生效
@ConditionalOnProperty 系统中指定属性存在指定的值时生效
@ConditionalOnResource 类路径下存在指定的资源文件时生效
@ConditionalOnWebApplication 当前应用是 web 应用时生效
@ConditionalOnNotWebApplication 当前应用不是 web 应用生效

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

ServletWebServerFactoryAutoConfiguration

ServletWebServerFactoryAutoConfiguration代码如下。

@Configuration(   //表示这是一个配置类,与 xml 配置文件等价,也可以给容器中添加组件
  proxyBeanMethods = false
)@AutoConfigureOrder(-2147483648)@ConditionalOnClass({ServletRequest.class})//判断当前项目有没有 ServletRequest 这个类@ConditionalOnWebApplication(// 判断当前应用是否是 web 应用,如果是,当前配置类生效
type = Type.SERVLET
)@EnableConfigurationProperties({ServerProperties.class})//启动指定类的属性配置(ConfigurationProperties)功能;将配置文件中对应的值和 ServerProperties 绑定起来;并把 ServerProperties 加入到ioc容器中@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})public class ServletWebServerFactoryAutoConfiguration { public ServletWebServerFactoryAutoConfiguration() {
 } @Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
 public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties, ObjectProvider<WebListenerRegistrar> webListenerRegistrars) {  return new ServletWebServerFactoryCustomizer(serverProperties, (List) webListenerRegistrars.orderedStream().collect(Collectors.toList()));
 } @Bean
 @ConditionalOnClass(
   name = {"org.apache.catalina.startup.Tomcat"}
 )
 public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {  return new TomcatServletWebServerFactoryCustomizer(serverProperties);
 } @Bean
 @ConditionalOnMissingFilterBean({ForwardedHeaderFilter.class})
 @ConditionalOnProperty(
   value = {"server.forward-headers-strategy"},
   havingValue = "framework"
 )
 public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
  ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
  FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean(filter, new ServletRegistrationBean[0]);
  registration.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.ASYNC, DispatcherType.ERROR});
  registration.setOrder(-2147483648);  return registration;
 } public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {  private ConfigurableListableBeanFactory beanFactory;  public BeanPostProcessorsRegistrar() {
  }  public void setBeanFactory(BeanFactory beanFactory) throws BeansException {   if (beanFactory instanceof ConfigurableListableBeanFactory) { this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
   }
  }  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {   if (this.beanFactory != null) { this.registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class, WebServerFactoryCustomizerBeanPostProcessor::new); this.registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::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 = new RootBeanDefinition(beanClass, instanceSupplier);
 beanDefinition.setSynthetic(true);
 registry.registerBeanDefinition(name, beanDefinition);
   }
  }
 }
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162复制代码类型:[java]

该类使用了以下注解:

@Configuration:用于定义一个配置类,可用于替换Spring中的xml配置文件;

@Bean:被@Configuration注解的类内部,可以包含有一个或多个被@Bean注解的方法,用于构建一个Bean,并添加到Spring容器中;该注解与spring配置文件中<bean>等价,方法名与<bean>的id或name属性等价,方法返回值与class属性等价;

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

@ConditionalOnClass({ServletRequest.class}):判断当前项目是否存在ServletRequest这个类,若存在,则该配置类生效。

@ConditionalOnWebApplication(type=Type.SERVLET):判断当前应用是否是Web应用,如果是的话,当前配置类生效。

@ConditionalOnClass(name={"org.apache.catalina.startup.Tomcat"}):判断是否存在Tomcat类,若存在则该方法生效。

@ConditionalOnMissingFilterBean({ForwardedHeaderFilter.class}):判断容器中是否有ForwardedHeaderFilter这个过滤器,若不存在则该方法生效。

@ConditionalOnProperty(value={"server.forward-headers-strategy"},havingValue="framework"):判断配置文件中是否存在server.forward-headers-strategy=framework,若不存在则该方法生效。

ServerProperties

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

@ConfigurationProperties(
 prefix = "server",
 ignoreUnknownFields = true
)public class ServerProperties { private Integer port; private InetAddress address; @NestedConfigurationProperty
 private final ErrorProperties error = new ErrorProperties(); private ServerProperties.ForwardHeadersStrategy forwardHeadersStrategy; private String serverHeader; private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8L); private Shutdown shutdown; @NestedConfigurationProperty
 private Ssl ssl; @NestedConfigurationProperty
 private final Compression compression; @NestedConfigurationProperty
 private final Http2 http2; private final ServerProperties.Servlet servlet; private final ServerProperties.Tomcat tomcat; private final ServerProperties.Jetty jetty; private final ServerProperties.Netty netty; private final ServerProperties.Undertow undertow; public ServerProperties() {  this.shutdown = Shutdown.IMMEDIATE;  this.compression = new Compression();  this.http2 = new Http2();  this.servlet = new ServerProperties.Servlet();  this.tomcat = new ServerProperties.Tomcat();  this.jetty = new ServerProperties.Jetty();  this.netty = new ServerProperties.Netty();  this.undertow = new ServerProperties.Undertow();
 }
 ....
}123456789101112131415161718192021222324252627282930313233343536复制代码类型:[java]

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

SpringBoot中为我们提供了大量的自动配置类XxxAutoConfiguration以及XxxProperties,每个自动配置类XxxAutoConfiguration都使用了@EnableConfigurationProperties注解,而每个XxxProperties上都使用@ConfigurationProperties注解。

@ConfigurationProperties注解的作用,是将这个类的所有属性与配置文件中相关的配置进行绑定,以便于获取或修改配置,但是@ConfigurationProperties功能是由容器提供的,被它注解的类必须是容器中的一个组件,否则该功能就无法使用。而@EnableConfigurationProperties注解的作用正是将指定的类以组件的形式注入到IOC容器中,并开启其@ConfigurationProperties功能。因此,@ConfigurationProperties+@EnableConfigurationProperties组合使用,便可以为XxxProperties类实现配置绑定功能。

自动配置类XxxAutoConfiguration负责使用XxxProperties中属性进行自动配置,而XxxProperties则负责将自动配置属性与配置文件的相关配置进行绑定,以便于用户通过配置文件修改默认的自动配置。也就是说,真正“限制”我们可以在配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

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

(0)

相关推荐