前言
上一篇讲述了 SpringBoot 启动流程和相关源码分析,其中一个重要的刷新方法 AbstractApplicationContext#refresh() 是属于 Spring 的内容,也是 Spring 框架的核心方法,搞懂了这个方法,基本上可以说就完全搞懂了 Spring
想了很久不知道对于这样一个复杂的框架,从何开始讲起,那么就按照 AbstractApplicationContext#refresh() 的内部代码顺序来吧,先学习 BeanFactoryPostProcessor。
本篇文章使用的版本是 SpringBoot 3.4.1 、 Spring 6.2.1。
SpringBoot & Spring 架构图示概览
这里我以 SpringBoot 源码入口为起点,画了一个相关的流程图,包含了 SpringBoot、Spring 事务、Spring AOP、Spring 事件、BeanFactoryPostProcessor、BeanPostProcessor 等所有 Spring 知识,以及相关模块之间的交互联系,后续也会持续更新此图(因为我自己还没有学完),我试了下作者侧这边更新后,分享的协作链接也会实时变更,希望对大家有帮助
SpringBoot & Spring 架构图 持续更新 对于即将需要面试的同学应该会比较有帮助!
前置知识 IoC 容器
IoC 全称 Inversion of Control,叫做控制反转,它是一种设计原则,其核心思想是将对象创建、依赖管理和生命周期控制的权力从应用程序代码 反转 给容器(框架)。
原本我们需要调用某个业务方法,需要自己实例化对象,然后调用该对象某个方法,使用 Spring 之后,我们把该对象交给 Spring 管理,Spring 框架帮我们创建对象,我们只需要拿 Spring 创建好的对象即可。而我们交给 Spring 管理的对象通常就叫做 Bean。
IoC 容器就是通常我们常说的 Spring 上下文,ApplicationContext 的实现类,对于 SpringBoot 来说,其扩展的实现类是 AnnotationConfigServletWebServerApplicationContext
java
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringAiDemoApplication.class, args);
}
SpringBoot 主类的 run 方法,其返回值就是一个 IoC 容器,ApplicationContext 的子接口
前置知识 BeanDefinition 和 Bean
在开始之前,我相信大家都是已经熟悉 Spring 框架的日常用法,我们需要有一个前置知识储备,在 Spring 容器中,Bean 的创建都是由 BeanDefinition 决定的, BeanDefinition 描述了这个 Bean 的所有信息
Bean的类型Bean的名字- 单例还是多例
- 是否延迟加载
- 是否允许自动装配
- 等等
比如我们使用 @Configuration、@Bean、@Component 注解一个 Bean。刷新方法中,先解析这些注解得到了 BeanDefinition 信息,当所有配置相关的注解被解析完,得到一个
java
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
然后 Spring 遍历这个 beanDefinitionNames 去创建 Bean。
因为 HashMap 是无序的,创建 Bean 需要根据顺序创建,所以需要这个 beanDefinitionNames
BeanFactoryPostProcessor 的作用
学习源码,最有效的方式之一就是看注释,
java
/**
* Factory hook that allows for custom modification of an application context's
* bean definitions, adapting the bean property values of the context's underlying
* bean factory.
* ......
*/
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
注释说明这个类的作用相当于一个工厂回调函数(通常我们叫它 Bean 工厂后置处理器),可以调整上下文的底层Bean 工厂的 Bean 属性值。也就是在 Bean 创建前,BeanDefinition 已默认加载后,修改某些 BeanDefinition 。因为 Bean 的创建是由 BeanDefinition 决定的,所以修改 BeanDefinition,也就相当于修改即将要创建的 Bean
内置的 BeanFactoryPostProcessor
在上一篇 SpringBoot 文章中,我们提到在创建 Spring 上下文的时候,AnnotationConfigServletWebServerApplicationContext 的构造方法中,会注册一些内置的 BeanFactoryPostProcessor。源码
java
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors()
内置会注册以下后置处理器
java
ConfigurationClassPostProcessor 处理所有配置注解 @Componentscan、@Import、@Bean、@Component 等
AutowiredAnnotationBeanPostProcessor 处理 @Autowired
CommonAnnotationBeanPostProcessor 处理 @PostConstruct、@Resource 等
PersistenceAnnotationBeanPostProcessor(如果用了 JPA)
EventListenerMethodProcessor 处理 @EventListener
DefaultEventListenerFactory (不是后置处理器,不知道为什么放在这个方法里)
这里只有 ConfigurationClassPostProcessor 和 EventListenerMethodProcessor 是工厂后置处理器 BeanFactoryPostProcessor,其他都是 Bean 的后置处理器 BeanPostProcessor,下一篇文章会介绍。在介绍 ConfigurationClassPostProcessor 和 EventListenerMethodProcessor 的作用之前,我们先学习一个 BeanFactoryPostProcessor 的扩展接口 BeanDefinitionRegistryPostProcessor。
BeanDefinitionRegistryPostProcessor
还是老规矩,学习一个类之前先看注释
java
/**
* Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
* the registration of further bean definitions <i>before</i> regular
* BeanFactoryPostProcessor detection kicks in. In particular,
* BeanDefinitionRegistryPostProcessor may register further bean definitions
* which in turn define BeanFactoryPostProcessor instances.
* @see org.springframework.context.annotation.ConfigurationClassPostProcessor
*/
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
注释说 BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的一个扩展接口。容器刷新过程中 postProcessBeanDefinitionRegistry() 在 postProcessBeanFactory() 之前执行,他们的区别和作用如下
和 BeanFactoryPostProcessor 的区别对比
这里用一个表格来对比 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 的方法
| 维度 | postProcessBeanDefinitionRegistry | postProcessBeanFactory |
|---|---|---|
| 执行时机 | 更早,在所有 BeanFactoryPostProcessor 之前 | 稍晚,在所有 postProcessBeanDefinitionRegistry 之后 |
| 参数类型 | BeanDefinitionRegistry |
ConfigurableListableBeanFactory |
| 主要用途 | 注册、修改、移除 BeanDefinition | 修改 已注册的 BeanDefinition,不能注册和移除 |
| 能力范围 | 注册新 Bean 的能力更强 | 修改现有 Bean 的属性 |
| 执行顺序 | 第一阶段 | 第二阶段 |
也就是说他们两都是对 BeanDefinition 做操作的,只不过时机不同
常见的 BeanFactoryPostProcessor
SpringBoot 项目中有一些内置的工厂后置处理器
ConfigurationClassPostProcessor解析配置类,获取BeanDefinitonEventListenerMethodProcessor初始化事件工厂,为了后续创建事件监听器PropertySourcesPlaceholderConfigurer处理配置类成员变量的值有属性占位符,比如有些Bean的某个属性值是${mybatis-plus.lazy-initialization}这种表达式,就是通过这个后置处理器来解析赋值MapperScannerConfigurer如果使用了mybatis,扫描@Mapper注解的类,添加到Spring容器CachingMetadataReaderFactoryPostProcessor缓存ResourceLoader已加载的配置类,不要重复加载
下面我们详细介绍其中几个重要的工厂后置处理器的作用。
BeanFactoryPostProcessor 的执行
工厂后置处理器的执行方法是通过一个委托类 PostProcessorRegistrationDelegate 实现的
java
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
这个方法非常有意思,作者在这里给出了一大段的注释,告诉读者不要再去 Github 提 issue 了,因为这个方法的代码看起来很乱、有很多重复代码,很多读者提了 issue 表明这个方法需要优化,但是作者一一拒绝,回应说这种实现是必要的,一定要确保工厂后置处理器的执行顺序。有兴趣可以查阅上述方法的源码

这里作者将 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 分开,并且将它们分别按照顺序排序放到不同列表中依次执行。
注意,这个阶段还没有创建
Bean,所以要执行的BeanFactoryPostProcessor,都是通过从BeanFactory里面的beanDefinitonNames集合拿到的,使用beanFactory.getBeanNamesForType()方法
配置类加载原理 (非常非常重要)ConfigurationClassPostProcessor
这是一个非常重要的 BeanFactoryPostProcessor,Spring 项目启动加载配置类几乎全都是它实现的,除了我们自己声明的 Service、Controller。 配置类本身也是 Spring Bean。
其实我们查看源码会发现 @Service、@Controller、@Configuration 本身就是一个 @Component。查看 @Component 的注释
vbnet
/**
* Indicates that the annotated class is a <em>component</em>.
*
* <p>Such classes are considered as candidates for auto-detection
* when using annotation-based configuration and classpath scanning.
*/
被这个注解标注的类都会被视为一个组件,在被扫描的时候会被认为是一个配置类
代码解读
ConfigurationClassPostProcessor 是一个 BeanDefinitionRegistryPostProcessor 。我们查看源码方法的调用过程 postProcessBeanDefinitionRegistry → processConfigBeanDefinitions → ConfigurationClassParser#parse → ConfigurationClassParser#processConfigurationClass → ConfigurationClassParser#doProcessConfigurationClass(arg1,arg2) → doProcessConfigurationClass(arg1,arg2,arg3)
先看 parse() 方法
java
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition annotatedBeanDef) {
parse(annotatedBeanDef, holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition abstractBeanDef && abstractBeanDef.hasBeanClass()) {
parse(abstractBeanDef.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);
}
}
this.deferredImportSelectorHandler.process();
}
我们传入的入参就是 SpringBoot 主类的 BeanDefinition,这个方法根据 BeanDefinition 实际的类型走不同的重载方法,SpringBoot 项目主类的定义类型是 AnnotatedBeanDefinition 。 接下来我们看 doProcessConfigurationClass(arg1,arg2)
java
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) {
//......
// 循环处理配置类,返回的 sourceClass 是父类,只要不为空就一直向上找父类循环处理
SourceClass sourceClass = null;
try {
sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
}
catch (IOException ex) {
//...
}
this.configurationClasses.put(configClass, configClass);
}
这里有一个循环,解析传入的配置类,返回该配置类的父类,如果该配置类的父类不为空,就一直解析。 接下来内部最直观的解析配置类的方法 doProcessConfigurationClass(arg1,arg2,arg3) 。
java
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 解析内部类。比如一个加了 @Configuration 的配置类,有一个静态内部类也加了 @Configuration
processMemberClasses(configClass, sourceClass, filter);
}
// 解析 @PropertySource 注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), org.springframework.context.annotation.PropertySource.class,
PropertySources.class, true)) {
if (this.propertySourceRegistry != null) {
this.propertySourceRegistry.processPropertySource(propertySource);
}
}
// 解析 @ComponentScans 注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(),ComponentScan.class, ComponentScans.class, MergedAnnotation::isDirectlyPresent);
if (componentScans.isEmpty()) {
componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScan.class, ComponentScans.class, MergedAnnotation::isMetaPresent);
}
if (!componentScans.isEmpty()) {
List<Condition> registerBeanConditions = collectRegisterBeanConditions(configClass);
for (AnnotationAttributes componentScan : componentScans) {
// 解析 @ComponentScan 注解(注意这里直接向 Spring 容器注册了 BeanDefiniton)
//其他注解解析都是先封装成一个 ConfigurationClass 对象,后续统一注册 BeanDefinition
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 检查 @ComponentScan 扫描到的配置类是否还有其他配置注解,例如 @Import,递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 解析 @Import 注解(SpringBoot 自动配置类的核心实现)
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//解析 @ImportResource 注解
AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 解析 @Bean 注解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
if (methodMetadata.isAnnotated("kotlin.jvm.JvmStatic") && !methodMetadata.isStatic()) {
continue;
}
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 解析当前类实现的接口里面加了 @Bean 的 default 方法
processInterfaces(configClass, sourceClass);
// 解析父类
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java")) {
boolean superclassKnown = this.knownSuperclasses.containsKey(superclass);
this.knownSuperclasses.add(superclass, configClass);
if (!superclassKnown) {
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
}
// No superclass -> processing is complete
return null;
}
我们可以继续阅读 processMemberClasses()、processImports() 等每一个具体解析注解的方法,会发现 这个解析方法的调用是一个递归的过程。先根据一个主配置类,在 SpringBoot 中就是应用启动主类。由于 @SpringBootApplication 内部组合了 @Configuration ,所以它是一个配置类,SpringBoot 会以主类为入口,从它开始扫描,然后由于 SpringBootApplication 内部组合了 @ComponentScan 注解,所以会解析主类所在的包下的所有配置类。然后由于它内部又组合了 SpringBootApplication → @EnableAutoConfiguration → @Import(AutoConfigurationImportSelector.class),所以会解析 AutoConfigurationImportSelector 获取的所有配置类。这也是 SpringBoot 自动配置的核心实现原理
SpringBoot 自动配置的核心原理
在 SpringBoot 文章中我们说过,这个 AutoConfigurationImportSelector 是 SpringBoot 自动配置的核心。从上面的解析方法 doProcessConfigurationClass(arg1,arg2,arg3) 我们知道它会解析 @Import 注解,然后我们看 processImports() 的源码
java
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// 处理 ImportSelector 的逻辑
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
filter = filter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector deferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, deferredImportSelector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, filter);
processImports(configClass, currentSourceClass, importSourceClasses, filter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// 处理 ImportBeanDefinitionRegistrar 的逻辑
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 处理普通配置类的逻辑
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
}
这里对于 @Import 有三种处理逻辑,相当于一个策略模式的体现
@Import(XxxImportSelector.class)执行selectImports获取导入的配置类@Import(XxxImportBeanDefinitionRegistrar.class)执行registerBeanDefinitions注册BeanDefinition@Import(XxxConfiguration.class)普通配置类,直接解析
对于 @Import 注解中的不同类型值,会进行不同的处理逻辑,但最终都是解析配置类,无非是导入的方式不同,具体我们可以看对应接口的方法说明。
注意对于
ImportSelector有两种处理方式,它有一个子接口DeferredImportSelector,延迟导入器,如果导入的是此类型,那么会执行其内部类DeferredImportSelector.Group#process
我们查看 AutoConfigurationImportSelector.AutoConfigurationGroup#process() 方法的源码,看它是怎么获取到自动配置类的
这里有一个点要注意,对于
SpringBoot的AutoConfigurationImportSelector是一个延迟导入器,获取导入的配置类列表不是直接调用AutoConfigurationImportSelector.selectImports()而是调用内部类AutoConfigurationGroup.process()和AutoConfigurationGroup.selectImports()
java
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//扫描 imports 文件获取自动配置类列表
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
java
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,getBeanClassLoader());
List<String> configurations = importCandidates.getCandidates();
return configurations;
}
java
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
String location = String.format(LOCATION, annotation.getName());
Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
List<String> importCandidates = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
importCandidates.addAll(readCandidateConfigurations(url));
}
return new ImportCandidates(importCandidates);
}
好了,这里有一个 LOCATION 常量,我们看他的值是写死的
arduino
private static final String LOCATION = "META-INF/spring/%s.imports";
这里传入的注解就是 @AutoConfiguration 的全类名,org.springframework.boot.autoconfigure.AutoConfiguration
java
public AutoConfigurationImportSelector() {
this(null);
}
AutoConfigurationImportSelector(Class<?> autoConfigurationAnnotation) {
this.autoConfigurationAnnotation = (autoConfigurationAnnotation != null) ? autoConfigurationAnnotation : AutoConfiguration.class;
}
替换掉 LOCATION 的占位符之后,我们得到完整的路径地址
ini
LOCATION = META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
然后我们再去看 MyBatisPlus、Redis、RabbitMQ 的 starter,我们都会看到这个路径下有这样的文件

这下恍然大悟了吧,那现在让你自己定义一个 springboot-starter,还觉得困难吗?
注意 SpringBoot 3.0 以前读取的是
spring.factories,之后改成了imports文件
配置类加载过程流程图

配置类递归解析流程图

下面的树形结构可能有助于进一步理解这个流程
ruby
/**
* Spring 配置类扫描解析的递归流程
*
* 示例配置结构:
* └── SpringBootApplication (@Configuration) [Level 0]
* ├── @ComponentScan("com.example") [Level 1]
* │ └── com.example.UserController (@Controller) [Level 2]
* │ └── @Configuration [Level 3]
* └── @Bean(appBean) [Level 1]
* ├── @Import(AutoConfigurationImportSelector.class) [Level 1]
* │ ├── @Configuration
* │ ├── @Import(DataSourceConfig.class) [Level 2]
* │ │ ├── @Configuration
* │ │ ├── @Import(RedisConfig.class) [Level 3]
* │ │ │ ├── @Configuration
* │ │ │ └── @Import(CacheConfig.class) [Level 4]
* │ │ │ ├── @Configuration
* │ │ │ └── @ComponentScan("com.cache")
* │ │ └── @Bean(dataSource)
* │ └── @Bean(service)
*/
只要当前正在扫描处理的配置类里面还有其他配置注解,就一直递归扫描解析,直到解析完毕为止。
特殊的 @ComponentScan
仔细观察源码会发现 @ComponentScan 注解的扫描过程中,使用 ComponentScanAnnotationParser 解析之后直接向 Spring 容器注册了 BeanDefinition 。而其他注解的扫描,例如 @Configuration、@Bean、@Import 都是将需要处理的配置类信息存储到 ConfigurationClassParser 的成员变量中。
java
//@ComponentScan 解析器
private final ComponentScanAnnotationParser componentScanParser;
//配置类集合
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
//延迟导入器处理器
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
此时还没有注册它们的 BeanDefinition
分类构建 BeanDefinition
上一段我们说了,前面的步骤解析完之后,只是把每一个配置类信息存储起来,抽象成一个 Map<ConfigurationClass, ConfigurationClass> configurationClasses,此时还没有向 Spring 容器中注册成 BeanDefiniton。我们可以查看源码,这个类里面有一些成员变量
java
final class ConfigurationClass {
//bean 名称
private String beanName;
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
//@Bean 方法集合
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
//@ImportResource 集合
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources = new LinkedHashMap<>();
//ImportBeanDefinitionRegistrar 集合
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars = new LinkedHashMap<>();
}
当所有配置类解析完成之后,得到一个全量集合 Map<ConfigurationClass, ConfigurationClass> ,然后在 ConfigurationClassPostProcessor#processConfigBeanDefinitions() 中调用 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions() 这一步执行完毕后,整个应用所有的配置都构建 BeanDefinition 加载完毕
EventListenerMethodProcessor
它是一个解析事件监听的后置处理器
java
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.originalEvaluationContext.setBeanResolver(new BeanFactoryResolver(this.beanFactory));
Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
this.eventListenerFactories = factories;
}
我们可以看到这个后置处理方法中,主要是对 eventListenerFactories 赋值,然后后续等所有单例 Bean 实例化完成后,会调用它的生命周期方法 EventListenerMethodProcessor#afterSingletonsInstantiated(),会用这个工厂创建事件监听器,添加到 ApplicationContext 中,Spring 事件机制 就是把所有事件监听器添加到 ApplicationContext 的 applicationListeners 字段中,调用 ApplicationEventPublisher#publishEvent(ApplicationEvent) 的时候从这里找到符合的监听器批量执行,相当于广播一个消息。
java
//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null && listener.supportsAsyncExecution()) {
try {
//异步事件
executor.execute(() -> invokeListener(listener, event));
}
catch (RejectedExecutionException ex) {
// Probably on shutdown -> invoke listener locally instead
invokeListener(listener, event);
}
}
else {
invokeListener(listener, event);
}
}
}
MapperScannerConfigurer
如果我们使用 Mybatis 框架的话,就会有这个工厂后置处理器
注册来源
上面我们知道 SpringBoot 启动后会先执行 ConfigurationClassPostProcessor 加载自动配置类,于是加载到了 MybatisPlusAutoConfiguration,它有一个静态内部类
java
@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
@Import(AutoConfiguredMapperScannerRegistrar.class)
@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
@Override
public void afterPropertiesSet() {
logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
}
}
这里 @Import 导入了 AutoConfiguredMapperScannerRegistrar 类,再查看AutoConfiguredMapperScannerRegistrar#registerBeanDefinitions 注册方法中注册了 MapperScannerConfigurer 的 BeanDefiniton 。
作用
我们查看 MapperScannerConfigurer#postProcessBeanDefinitionRegistry,源码很简单
java
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
//解析属性值中的占位符
processPropertyPlaceHolders();
}
//实例化 `ClassPathBeanDefinitionScanner` 的实现类扫描类路径下的 @Mapper 注解
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
if (StringUtils.hasText(defaultScope)) {
scanner.setDefaultScope(defaultScope);
}
scanner.registerFilters();
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
就是把类路径下的 @Mapper 注解的类扫描出来注册为 BeanDefiniton 。
自我扩展
参考 MapperScannerConfigurer 假设我们后续需要自己制作一个组件,读取 @Xxx 标注的类注册为 BeanDefiniton 交给 Spring ,是不是就很简单了~
CachingMetadataReaderFactoryPostProcessor
这个类是 SpringBoot 提供的一个重要的缓存元信息的工厂后置处理器,它是通过 ApplicationContextInitializer 添加到 ApplicationContext 中的
java
class SharedMetadataReaderFactoryContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered, BeanRegistrationExcludeFilter {
public static final String BEAN_NAME = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory";
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
if (AotDetector.useGeneratedArtifacts()) {
return;
}
BeanFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(applicationContext);
applicationContext.addBeanFactoryPostProcessor(postProcessor);
}
}
我们可以查看 CachingMetadataReaderFactoryPostProcessor#postProcessBeanDefinitionRegistry 后置处理方法源码,
java
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
register(registry);
configureConfigurationClassPostProcessor(registry);
}
先注册了一个 SharedMetadataReaderFactoryBean 的 BeanDefiniton ,实际上最后就是向容器中注入 ConcurrentReferenceCachingMetadataReaderFactory,然后第二行代码很关键,给 ConfigurationClassPostProcessor 这个工厂后置处理器的属性 metadataReaderFactory 赋值为刚刚创建的 ConcurrentReferenceCachingMetadataReaderFactory
我们再去看原生的 ConfigurationClassPostProcessor.metadataReaderFactory 默认值
java
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
在判断一个类是不是配置类的时候会用到它,默认的实现是每次都会用资源加载器读取一遍这个类,
java
@Override
public MetadataReader getMetadataReader(String className) throws IOException {
try {
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
//重新读取文件
Resource resource = this.resourceLoader.getResource(resourcePath);
return getMetadataReader(resource);
}
}
而 ConcurrentReferenceCachingMetadataReaderFactory 的实现是,第一次读取之后放入缓存,后续每次获取会先从缓存中查询
java
@Override
public MetadataReader getMetadataReader(String className) throws IOException {
//读取缓存
MetadataReader metadataReader = this.classNameCache.get(className);
if (metadataReader == null) {
metadataReader = super.getMetadataReader(className);
this.classNameCache.put(className, metadataReader);
}
return metadataReader;
}
它的作用就是提高程序性能,避免重复读取类的元数据信息
BeanFactoryPostProcessor 与 BeanPostProcessor 对比
这两个名字很像,这里列出它们的区别,下一篇文章会详细介绍 BeanPostProcessor
| 对比维度 | BeanFactoryPostProcessor | BeanPostProcessor |
|---|---|---|
| 处理时机 | Bean 定义加载之后,Bean 实例化之前 | Bean 实例化之后,初始化回调前后 |
| 作用对象 | Bean 的定义元数据(BeanDefinition) | Bean 实例对象 |
| 主要功能 | 修改、注册或移除 BeanDefinition | 修改或包装 Bean 实例 |
| 执行阶段 | postProcessBeanFactory() |
postProcessBeforeInitialization() postProcessAfterInitialization() |
| 触发次数 | 每个容器仅执行一次 | 对每个 Bean 实例都会执行 |
| Spring 核心阶段 | BeanFactory 准备阶段 | Bean 生命周期阶段 |
| 典型应用场景 | 1. 修改 Bean 的属性值(占位符解析) 2. 动态注册 BeanDefinition 3. 根据条件移除 Bean | 1. 代理增强(AOP) 2. 属性注入后的处理 3. 自定义初始化逻辑 |
| 实现示例 | PropertySourcesPlaceholderConfigurer ConfigurationClassPostProcessor |
AutowiredAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor |
结语
篇幅原因,这里无法列出所有的工厂后置处理器的具体作用和实现,不过 SpringBoot 启动过程中,Spring 容器刷新过程中调用的 BeanFactoryPostProcessor 相对于 BeanPostProcessor 要少的多,但是两者都很重要,有兴趣可以逐一查看源码。