|------------------------------------------------------------------------------------------|
| ### 引言 > Spring Boot
自动装配是Spring Boot
框架的一个关键特性,它的目标是让开发者能够快速构建Spring
应用程序,减少繁琐的配置工作。 |
一、注解解析
@SpringApplication
从启动类@SpringApplication
注解入手,@SpringBootApplication
是一个组合注解,它是Spring Boot
框架中常用的一个主要注解之一。它结合了多个注解,简化了Spring Boot
应用程序的配置。
java
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
@SpringBootApplication
包含以下三个核心注解:
@SpringBootConfiguration
:这是Spring Boot
框架中的一个元注解,用于标识该类为Spring Boot
的配置类。配置类是用来定义Bean
和配置应用程序的类。@EnableAutoConfiguration
:这个注解告诉Spring Boot
根据类路径下的依赖和配置自动配置Spring
应用程序。它利用了Spring Boot
的自动配置特性,根据条件化配置的原理,自动配置所需的Bean
、组件和属性。@ComponentScan
:这个注解用于指定Spring Boot
扫描组件的基础包。Spring Boot会扫描这个包及其子包,查找带有注解(例如@Controller
、@Service
、@Repository
、@Component
等)的类,并将它们注册为Spring
管理的Bean
。
java
@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 {
...省略
}
EnableAutoConfiguration
是自动装配的核心,下面我们对该注解展开分析。
@EnableAutoConfiguration
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...省略
}
在@EnableAutoConfiguration
的源码中,可以看到它使用@Import
注解引入了AutoConfigurationImportSelector
类。当Spring bean后置处理器扫描解析启动类下所有包创建beanDefinition
时,AutoConfigurationImportSelector
会触发自动装配的加载过程。
@Import扩展点
@Import
是一个用于导入其他配置类的扩展点。通过使用@Import
注解,我们可以在一个配置类中引入其他的配置类,从而将它们的Bean定义和配置合并到当前配置中。
@Import
导入配置类分为两种:
- 实现
ImportSelector
接口的类,执行selectImports()
返回一个字符串数组,其中包含要导入的配置类的全限定名。 - 实现
ImportBeanDefinitionRegistrar
接口的类,执行registerBeanDefinition()
可以动态地注册Bean定义,从而实现更复杂的配置。
通过上述可知AutoConfigurationImportSelector
实现ImportSelector
接口。该自动装配核心类逻辑在接下的分析中展开说
二、spring boot 自动装配原理分析
初始化SpringApplication
java
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
//第一步
SpringApplication.run(MyApp.class, args);
}
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//第二步
return new SpringApplication(primarySources).run(args);
}
//第三步
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//资源加载器
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//设置启动引导类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//web应用类型:
// 1. NONE 非web应用程序
// 2. SERVLET web应用程序
// 3. REACTIVE 响应式web引用程序
//通过web应用类路径选择web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//Spring SPI机制获取key为 ApplicationContextInitializer的类,并将它们作为应用程序上下文初始化器(ApplicationContextInitializer)注册
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//Spring SPI机制获取key为 ApplicationListener,并将它们作为应用程序事件监听器(ApplicationListener)注册
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
这块关注第一次调用Spring SPI机制的setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
Spring SPI机制
java
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//Spring SPI机制加载 META-INF/spring.factories 文件以key,value形式的自动装配类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
通过 SpringFactoriesLoader.loadFactoryNames(type, classLoader)
方法,从 META-INF/spring.factories
文件中加载指定接口类型的实现类的名称集合,并将它们保存在一个 Set
中。
META-INF/spring.factories
: 通常是用于自动装配的配置文件,其包含了需要自动装配的类的全限定名。
一些八股文认为在
AutoConfigurationImportSelector
使用Spring SPI
加载META-INF/spring.factories
获取自动装配类 ,其实不然,Spring SPI
只加载一次META-INF/spring.factories
,以key-value的形式进行本地缓存,后续触发自动装配时,从本地缓存中获取自动装配类集合
Spring Boot启动的核心逻辑
java
public ConfigurableApplicationContext run(String... args) {
.
.省略
.
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//初始化并配置应用程序的环境,包括加载配置文件、解析命令行参数、设置系统属性等。
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//打印Banner
Banner printedBanner = printBanner(environment);
//根据web类型创建ApplicationContext
context = createApplicationContext();
//SpringBootExceptionReporter用于报告Spring Boot应用程序启动过程中的异常
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备ApplicationContext,包括设置环境、配置监听器、初始化Bean等操作。
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//这里会完成整个Spring IoC容器的初始化,包括解析Bean的定义,创建Bean实例,以及处理依赖注入等。
refreshContext(context);
.
.省略
.
return context;
}
上述代码中,除了createApplicationContext()
、refreshContext(context)
,其他部分与自动装配无关。在后续的文章中,会进一步介绍这部分内容。
createApplicationContext()做了什么?
java
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
//根据webApplicationType枚举类型,创建应用
switch (this.webApplicationType) {
case SERVLET: //SERVLET web应用程序
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE: //REACTIVE 响应式web引用程序
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default: //NONE 非web应用程序
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
public AnnotationConfigServletWebServerApplicationContext() {
//用于读取基于注解的Bean定义的类
this.reader = new AnnotatedBeanDefinitionReader(this);
//用于扫描类路径中的组件,并将其注册为Spring管理的Bean定义。
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//注册BeanFactory后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//注册BeanFactory后置处理器
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
.
.省略
.
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//自动装配重点:创建BeanFactory后置处理器 ConfigurationClassPostProcessor,用于扫描解析启动类当前包以及子包下的配置类
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
//注册 ConfigurationClassPostProcessor
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//创建BeanFactory后置处理器 CommonAnnotationBeanPostProcessor,处理依赖注入@Resource、WebServiceRef标注的字段以及方法
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
//注册CommonAnnotationBeanPostProcessor
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
.
.省略
.
return beanDefs;
}
上述这段代码整体来说非常简单,根据 web应用类型创建ApplicationContext
, 例如web应用类型为 SERVLET,创建AnnotationConfigServletWebServerApplicationContext
。通过AnnotationConfigServletWebServerApplicationContext
构造方法创建 AnnotatedBeanDefinitionReader
以及ClassPathBeanDefinitionScanner
,我们需要注意的是AnnotatedBeanDefinitionReader
涉及BeanFactory
后置处理器注册的内容,可以看到这一步注册了ConfigurationClassPostProcessor
-
AnnotatedBeanDefinitionReader
: 用于读取基于注解的Bean定义的类 -
ClassPathBeanDefinitionScanner
: 用于扫描类路径中的组件 -
ConfigurationClassPostProcessor
: 用于扫描解析启动类当前包以及子包下的配置类
refreshContext(context)做了什么?
java
@Override
public void refresh() throws BeansException, IllegalStateException {
...省略
/**
* 共注册了2个后置处理器
* ApplicationContextAwareProcessor,用于执行xxxAware接口中的方法
* ApplicationListenerDetector,保证监听器被添加到容器中
*/
prepareBeanFactory(beanFactory);
try {
//为容器的某些子类指定特殊的BeanPost事件处理器
postProcessBeanFactory(beanFactory);
//触发BeanFactory后置处理器
//定位注册加载BeanDefinition, 能让我们对容器中扫描出来的BeanDefinition做出修改以达到扩展的目的
invokeBeanFactoryPostProcessors(beanFactory);
//说白了就是beanFactory.addBeanPostProcessor(postProcessor);添加bean后置处理器
registerBeanPostProcessors(beanFactory);
初始化容器事件传播器,添加事件传播器到IOC容器
initApplicationEventMulticaster();
//启动容器
onRefresh();
//为事件传播器注册事件监听器.
registerListeners();
//将解析的BeanDefinition注册到IOC容器中
finishBeanFactoryInitialization(beanFactory);
//初始化容器的生命周期事件处理器,并发布容器的生命周期事
finishRefresh();
}
...省略
}
在refreshContext
方法中,完成了整个Spring IoC
容器的初始化,包括解析Bean
的定义、创建Bean
实例以及处理依赖注入等。我们主要关注invokeBeanFactoryPostProcessors(beanFactory)
对配置类进行定位解析注册BeanDefinition
invokeBeanFactoryPostProcessors(beanFactory)做了什么?
java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//遍历内部所有BeanDefinitionRegistry后置处理器 (继承 BeanFactoryPostProcessor),
//调用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 解析配置类成benaDefinition并注册
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
//第二步:
在invokeBeanFactoryPostProcessors
方法中,会触发所有BeanFactory
后置处理器的执行,其中ConfigurationClassPostProcessor
后置处理器负责扫描解析启动类当前包以及子包下的配置类,并将其注册为Spring
管理的BeanDefinition
,接下来我们就看看它的源码
ConfigurationClassPostProcessor源码分析
java
//调用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
//获取传入的 BeanDefinitionRegistry 对象 registry 的哈希码,作为标识
int registryId = System.identityHashCode(registry);
//通过检查 registriesPostProcessed 集合和 factoriesPostProcessed 集合,防止了在同一个 BeanDefinitionRegistry 上重复执行逻辑
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
//第三步
processConfigBeanDefinitions(registry);
}
//处理一些自定义的BeanDefinition
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的类
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//判断是否已经处理
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的类
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
...省略
// 创建配置类解析器,构造方法会创建ComponentScanAnnotationParser扫描器
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//1.解析
parser.parse(candidates);
//验证
parser.validate();
// 已经解析过的配置类
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 移除已经解析过的配置类,防止重复加载了配置类中的bd
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 2. 将所有ConfigurationClass解析成BeanDefinition进行 @Condition... 匹配,然后注册到beanDefinition容器中
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
// 如果大于,说明容器中新增了一些BeanDefinition,那么需要重新判断新增的bd是否是配置类,如果是配置类,需要再次解析
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
// 注册ImportRegistry到容器中
// 当通过@Import注解导入一个全配置类A(被@Configuration注解修饰的类),A可以实现ImportAware接口
// 通过这个Aware可以感知到是哪个类导入的
if (sbr != null) {
if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
//解析
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
// 在 new SpringApplication时候,会将 启动类 生成为AnnotatedBeanDefinition,然后注入到beanDefinition容器中
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
//注解类解析方式
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
//普通类解析方式
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//处理启动类的自动装配注解上@Import,对于 实现ImportSelector接口的执行selectImport
processDeferredImportSelectors();
}
private void processDeferredImportSelectors() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
if (deferredImports == null) {
return;
}
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
// 获取启动类上的所有@Import的实现ImportSelector类,执行selectImports
// 自动装配就在此处触发,获取类处境
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
// 处理selectImports返回的可导入自动装配类
//1. 实现imporselect接口,则创建为实例调用selectImprot方法,然后递归调用处理import
//2. 实现importRegistry接口,则缓存到importBeanDefinitionRegistrars集合
//3. 非上述接口,则当做配置类处理。解析@PropertySources、@ComponentScans、@Import、@Bean
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
}
}
上述代码主要流程:
-
配置类解析器进行解析
- 注解方式解析
- 解析启动类
@ComponentScans
注解信息获取basePackages
、basePackageClasses
,没有则将启动类包路径 - 创建
ClassPathBeanDefinitionScanner
对当前包以及子包下所有后缀.class文件进行扫描解析
@Component
、@Controller
、@Service
、@Repository
以及@Configura
配置类的@PropertySources
、@Import
、@Bean
生成ConfigurationClass
- 将
ConfigurationClass
与excludeFilters
进行排除过滤、Conditional
进行条件匹配
- 解析启动类
- 处理启动类上的
@Import
扩展点
- 注解方式解析
-
将所有
ConfigurationClass
解析成BeanDefinition
与@ConditiOnXXX
进行条件匹配,最后注册到BeanDefinition
容器中
@bean 等价于 factory-method
@bean 所在的类 等价于 factory-bean
自动装配核心逻辑 - AutoConfigurationImportSelector
java
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//加载组件自动配置类元信息spring-autoconfigure-metadata.properties
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取key为EnableAutoConfiuration对应的value集合
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//自动装配类去重
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//根据maven导入的启动器,过滤出需要导入的自动装配类
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
上面这段代码主要做了四件事
- 加载
spring-autoconfigure-metadata.properties
文件得到组件自动装配类元信息 - 从
Spring SPI
本地缓存中获取key
为EnableAutoConfiuration
对应的自动装配类集合 - 使用
LinkedHashSet
对自动装配类做去重操作 - 将自动配置类与
spring-autoconfigure-metadata.properties
进行条件匹配过滤出需要导入的自动装配类 (例如@ConditionalOnClass
) - 返回自动装配类数组
通过本文前部分的注解分析已知AutoConfigurationImportSelector
实现ImportSelector
接口。当ConfigurationClassPostProcessor
后置处理器处理@Import
时,就会触发自动装配核心类AutoConfigurationImportSelector#selectImprot()
获取Spring SPI
本地缓存key
为EnableAutoConfiuration
的自动装配类集合,然后去重过滤返回需要导入的自动装配类数组。
三、小结
简单的来说,Spring Boot的自动装配原理主要依赖于Spring SPI
机制+@Import
扩展点+ ConfigurationClassPostProcessor
实现。ConfigurationClassPostProcessor
后置处理器会在扫描解析启动类当前包以及子包下的配置类,并将其注册为Spring管理的BeanDefinition
,从而实现自动装配。而AutoConfigurationImportSelector
作为自动装配核心类,在处理@Import逻辑中触发自动装配的过程,最终获取需要导入的自动装配类集合,实现Spring Boot的自动装配功能。