【springboot源码】springboot自动配置原理分析
注:本文阅读前提,对springboot基本使用有所了解,此外,其他一些源码解读,如果有需要,可以参考:
- 【Spring源码】 后置处理器BeanPostProcessor底层原理分析
- 【spring源码】spring声明式事务底层源码分析
- 【spring源码】ApplicationListener事件监听底层原理
- 【spring源码】AOP底层源码分析
- 【spring源码】spring IOC容器底层源码分析
- 【SpringMVC源码】SpringMVC核心DispatcherServlet底层源码分析
- 【mybatis源码】 mybatis底层源码分析
1.测试用例
- 先搞个springboot项目来做测试用例
- pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>source-code</artifactId>
<groupId>com.source.code</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot</artifactId>
<!--版本控制-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Cairo-SR7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--Spring Boot将所有的功能场景都抽取出来,做成一个个的starters(启动器),-->
<!-只需要在项目里面引入这些starter 相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Spring Boot进行单元测试的模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--可运行jar包打包插件-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
- springboot启动主程序
/**
* 启动器
*@SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
* @author wangjie
* @version V1.0
* @date 2020/2/9
*/
@SpringBootApplication
public class ApplicationStart {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(ApplicationStart.class, args);
}
}
2.springboot自动配置原理分析
- 用springboot构建项目的优势不再赘述,有兴趣可以自行百度,今天我们对其自动配置功能做个探究
- 入口就是springboot的主程序:
/**
* 启动器
*@SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
* @author wangjie
* @version V1.0
* @date 2020/2/9
*/
@SpringBootApplication
public class ApplicationStart {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(ApplicationStart.class, args);
}
}
- 注解@SpringBootApplication: 注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot 就通过运行这个类的main方法来启动SpringBoot应用:
- 我们来看一下这个@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 {
- @SpringBootConfiguration:Spring Boot的配置类注解, 标注在某个类上,表示这是一个Spring Boot的配置类;
- @EnableAutoConfiguration:开启自动配置功能;今天聊的重点,springboot自动配置就是它在起作用
2.1 @EnableAutoConfiguration 开启自动配置功能
- 我们打开@EnableAutoConfiguration:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
- 我们挑重点来看:
- @AutoConfigurationPackage自动配置包
- @Import(AutoConfigurationImportSelector.class):@Import,Spring的底层注解,用来给容器中导入一个组件:AutoConfigurationImportSelector
- 这两个重点注解我们一个一个来看:
2.1.1 @AutoConfigurationPackage:自动配置包注解
- @AutoConfigurationPackage:自动配置包,简单说就是springboot在进行开启包扫描功能时,包扫描路径就是通过这个注解拿到的
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
- @AutoConfigurationPackage又是通过 @Import(AutoConfigurationPackages.Registrar.class)注解来完成的功能。
- @Import(AutoConfigurationPackages.Registrar.class):Spring的底层注解@Import,给容器中导入一个组件:AutoConfigurationPackages.Registrar.class;
- 我们来看一下这个类:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
//给ioc容器注册一些bean定义信息
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
- 我们来看看这个类中的registerBeanDefinitions()方法,它的作用是给ioc容器中注册一些bean定义信息,好在ioc容器创建时来创建这些bean。
- 首先来看方法入参metadata,它是注解的源信息,我们可以通过Debug来看一下:
- 可以看到这个源信息里标注了这是@SpringBootApplication注解,是标注在ApplicationStart类上的。
- 重点是在new PackageImport(metadata).getPackageName()这行代码。
- 我们Debug算一下它的结果:
- 得到了我们主类的包路径:com.code.
- 所以我们可以得到结论:AutoConfigurationPackages.Registrar.class这个组件的功能就是将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器。
- 包扫描的路径拿到了,我们来看@EnableAutoConfiguration中下一个重要的注解@Import(AutoConfigurationImportSelector.class)
2.1.2 @Import(AutoConfigurationImportSelector.class)
- @Import是Spring的底层注解,在这里用来给容器中导入一个组件:AutoConfigurationImportSelector
- 我们来看一下这个AutoConfigurationImportSelector
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {,,,}
- AutoConfigurationImportSelector实现了DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,BeanFactoryAware, EnvironmentAware, Ordered等六个接口。
- 其中类似BeanFactoryAware这样XXXAware这样的接口,功能都是类似的,就是在bean初始化的时候给bean中设置组件。
- 简单说就是spring IOC容器会在实现了类似接口的bean实例化时调用一个invokeAwareMethods方法:
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
- 当然除了代码中的几个,其他类似的接口也会通过后置处理器来给bean中设置组件,具体这里就不歪楼了,感兴趣可参考:
- 【spring源码】spring IOC容器底层源码分析
- 【Spring源码】 后置处理器BeanPostProcessor底层原理分析
- 除了这几个接口,还有个Ordered接口,它是用来进行优先级排序的,数值越小优先级越高,我们看一下它在AutoConfigurationImportSelector中的实现。
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 1;// 2147483646感觉不怎么高
}
- 最后聊重点的DeferredImportSelector接口,AutoConfigurationImportSelector最核心的代码就是对此接口的实现,在看具体代码前,我们先来看看这个接口,看看它是用来做什么的:
public interface DeferredImportSelector extends ImportSelector {}
- DeferredImportSelector 继承了ImportSelector ,我们打开ImportSelector :
/**
* Interface to be implemented by types that determine which @{@link Configuration}
* class(es) should be imported based on a given selection criteria, usually one or more
* annotation attributes.
*
* <p>An {@link ImportSelector} may implement any of the following
* {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
* methods will be called prior to {@link #selectImports}:
* <ul>
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li>
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li>
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li>
* </ul>
*
* <p>ImportSelectors are usually processed in the same way as regular {@code @Import}
* annotations, however, it is also possible to defer selection of imports until all
* {@code @Configuration} classes have been processed (see {@link DeferredImportSelector}
* for details).
*
* @author Chris Beams
* @since 3.1
* @see DeferredImportSelector
* @see Import
* @see ImportBeanDefinitionRegistrar
* @see Configuration
*/
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
- 此接口上的英文说明大概意思是:
1,最基本的功能是向IOC容器里导入自定义bean
2,如果实现了此接口的bean也实现了EnvironmentAware ,BeanFactoryAware,BeanClassLoaderAware,ResourceLoaderAware这些接口,要先调用这些接口的实现
3,如果需要在所有 @Configuration配置都实例化时候再进行实例化,可以使用此接口的变种子类DeferredImportSelector
- 而我们这里的这个bean ,就是实现了其变种子类DeferredImportSelector
- 对于ImportSelector 接口的使用,我们可以写个Demo:
- Demo:
/**
* 自定义返回需要导入的组件
* @see org.springframework.context.annotation.ImportSelector#selectImports(AnnotationMetadata)
*
* @author wangjie
* @version V1.0
* @date 2020/1/6
*/
public class MyImportSelector implements ImportSelector {
/**
*
* @param annotationMetadata 当前标注@Import的类所有注解信息 {@link org.springframework.core.type.AnnotationMetadata}
* @return 导入到容器中组件全类名
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.code.bean.Car"};
}
}
- 配置文件:
/**
* 配置文件
*
* @author wangjie
* @version V1.0
* @date 2020/1/5
*/
@Configuration
@Import({Home.class, MyImportSelector.class})
public class MyConfig3 {
}
- 测试用例:
@Test
public void test01(){
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
}
- 运行结果:
myConfig3
com.code.bean.Home
com.code.bean.Car
Process finished with exit code 0
- com.code.bean.Car是空的个实体类,这里就不贴了
- 搞清楚了这个接口的作用,我们再回过头来看AutoConfigurationImportSelector对DeferredImportSelector的实现:
//这个方法就是来告诉springboot要导那些组件,方式就是通过String[]数组将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中,具体类似上方Demo
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//重点
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
//一顿操作,最后返回数组
return StringUtils.toStringArray(configurations);
}
- 这个方法就是来告诉springboot要导那些组件,方式就是通过String[]数组将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中,具体类似上方Demo
- 具体拿数组的方法就是List configurations = getCandidateConfigurations(annotationMetadata,
attributes);这行代码,我们点进去:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
- 这个方法中重点是调用了SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
- 其中入参getSpringFactoriesLoaderFactoryClass()
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
- 拿到的是EnableAutoConfiguration.class这个自动加载工厂的名字
- 另一个入参getBeanClassLoader是类加载器:
- 我们对这个方法跟踪下去,会看到这样一个方法:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
//保存工厂类名字
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//用类加载器加载本地文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 把类加载器加载出的资源转成Properties 文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
//遍历该配置文件key
for (Map.Entry<?, ?> entry : properties.entrySet()) {
//把properties解析到LinkedMultiValueMap中返回
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
-
这个方法重要的主要分三步:
-
第一步:用类加载器加载本地资源
-
加载的文件路径:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
- 第二步:把加载到的资源用key:value的形式保存到LinkedMultiValueMap中
- 第三步:通过之前传进来的工厂类名字做key,从LinkedMultiValueMap拿到要返回的数组。
- 最后,我把springboot META-INF/spring.factories目录下的配置文件中我们需要的部分贴一下,这里会被自动注册的组件就是它们:
# 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.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.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.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.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
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.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
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.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.groovy.template.GroovyTemplateAutoConfiguration,\
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.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.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
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.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
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.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.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
- 它们会被解析成数组返回,再通过DeferredImportSelector接口注册进IOC容器中完成自动配置
【完】