Spring 版本: 6.0.6
BeanFactory 的后置处理器的作用
BeanFactory
的后置处理器(PostProcessor
)是用于在 BeanFactory
加载和创建 bean
过程中对 bean
进行进一步处理的接口。它提供了一种机制,可以在 Spring
容器实例化 bean
之前对 bean
进行定制、修改或扩展
两种 BeanFactory 的接口类型
BeanFactoryPostProcessor
可以通过 ConfigurableListableBeanFactory
对 BeanDefinition
进行修改,这样就会改变 bean
的定义
java
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor
继承了 BeanFactoryPostProcessor
接口,同时增加了一个接口,该接口提供了 BeanDefinitionRegistry
参数,也就是可以动态注入一些 BeanDefinition
, 在 Spring
中典型的应用是 ConfigurationClassPostProcessor
,后面会分析这个类
java
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
BeanFactory 后置处理器的使用示例
使用示例类说明
CusBeanFactoryPostProcessor
该类实现了BeanFactoryPostProcessor
接口并且标有@Component
注解CusBeanDefinitionRegistryPostProcessor
该类实现了BeanDefinitionRegistryPostProcessor
接口并且标有@Component
注解RegisterComponent
普通类,会通过CusBeanDefinitionRegistryPostProcessor
注入到Spring
容器ScanComponent
标有@Component
和@Scope("prototype")
, 会通过CusBeanFactoryPostProcessor
将scope
从prototype
改为singleton
BeanFactoryPostProcessMain
主类,标有@Configuration
和@ComponentScan
上述所有类都放在同一个包中
java
// 普通类,并没有增加spring注解,会通过 CusBeanDefinitionRegistryPostProcessor 注入到 Spring 容器
public class RegisterComponent {
public void sayHello() {
System.out.println("RegisterComponent.sayHello");
}
}
// 实现了BeanDefinitionRegistryPostProcessor接口,会被spring扫描,并且注入了普通类 RegisterComponent
@Component
public class CusBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(RegisterComponent.class).getBeanDefinition();
registry.registerBeanDefinition("registerComponent", beanDefinition);
System.out.println("CusBeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("CusBeanDefinitionRegistryPostProcessor postProcessBeanFactory");
}
}
// 被spring管理的类,如果没有任何处理会是 prototype 作用域, 这里会通过 CusBeanFactoryPostProcessor 将 scope 改为 singleton
@Component
@Scope("prototype")
public class ScanComponent {
public void sayHello() {
System.out.println("BeanFactoryDemo1 sayHello");
}
}
// 实现了BeanFactoryPostProcessor接口,会将scanComponent类的scope从prototype改为singleton
@Component
public class CusBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition scanComponent = beanFactory.getBeanDefinition("scanComponent");
scanComponent.setScope("singleton");
System.out.println("CusBeanFactoryPostProcessor postProcessBeanFactory");
}
}
// 配置主类
@Configuration
@ComponentScan
public class BeanFactoryPostProcessMain {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanFactoryPostProcessMain.class);
// BeanFactoryPostProcessor 的测试(修改了 ScanComponent 类的 scope 属性)
ScanComponent bean = context.getBean(ScanComponent.class);
System.out.println(bean);
ScanComponent bean2 = context.getBean(ScanComponent.class);
System.out.println(bean2);
RegisterComponent registerComponent = context.getBean(RegisterComponent.class);
registerComponent.sayHello(); // 会打印 "RegisterComponent.sayHello"
}
}
执行结果
java
CusBeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry
CusBeanDefinitionRegistryPostProcessor postProcessBeanFactory
CusBeanFactoryPostProcessor postProcessBeanFactory
org.example.beanfactorypost.ScanComponent@5e1fa5b1
org.example.beanfactorypost.ScanComponent@5e1fa5b1
RegisterComponent.sayHello
从上面执行结果可以得出如下几个结论:
- 先执行实现了
BeanDefinitionRegistryPostProcessor
接口的类,然后才是执行的BeanFactoryPostProcessor
接口实现类 BeanDefinitionRegistryPostProcessor
实现类确实可以注册普通对象成为bean
, 比如上面注册了普通对象RegisterComponent
CusBeanFactoryPostProcessor
类已经将ScanComponent
的scope
属性改成singleton
, 因为两次getBean
获取的是同一个对象
BeanFactory 后置处理器的执行时机
参考 [[Spring上下文refresh方法解析]] 中写到的 refresh()
方法的第五步,就是执行后置处理器
执行流程如下
所以最终是执行到 public PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
方法 , 代码这里就不贴了,这里总结一下
- 执行实现了
BeanDefinitionRegistryPostProcessors
和PriorityOrdered
的类的postProcessBeanDefinitionRegistry()
方法 - 执行实现了
BeanDefinitionRegistryPostProcessors
和Ordered
的类的postProcessBeanDefinitionRegistry()
方法 - 执行实现了
BeanDefinitionRegistryPostProcessors
并且在 前面两步中没有执行过的类 - 对于实现了
BeanFactoryPostProcessor
的类,调用流程也是类似,执行实现了PriorityOrdered
的类 -> 执行实现了Ordered
的类 -> 执行剩下的类
BeanDefinitionRegistryPostProcessor 典型实现类 ConfigurationClassPostProcessor
在 Spring
内部也是有很多实现了 BeanDefinitionRegistryPostProcessor
接口的类,比如 ConfigurationClassPostProcessor
类,下面就来看看这个类
- 先说明一下
ConfigurationClassPostProcessor
这个类做的事情,在Spring
中@ComponentScan
注解可以批量扫描类被Spring
管理,但是注解只是起到一个标记的作用,需要有地方来解析这个注解才行,而这个解析的源头就是ConfigurationClassPostProcessor
,真正解析是在ConfigurationClassParser
中 - 前面有说过
BeanDefinitionRegistryPostProcessors
接口的实现类可以批量注册BeanDefinition
被Spring
管理,在ConfigurationClassParser
中将@ComponentScan
涉及到的类都解析出来之后,刚好就可以注册到Spring
容器中
代码执行流程如下
csharp
AbstractApplicationContext#refresh
AbstractApplicationContext#invokeBeanFactoryPostProcessors
public PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
private PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
ConfigurationClassPostProcessor#processConfigBeanDefinitions
ConfigurationClassParser#parse
ComponentScanAnnotationParser#parse
上面是代码的整体执行流程, 最终是通过 ComponentScanAnnotationParser
来进行解析 @ComponentScan
注解的
问题
上面代码执行流程中,在 PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
中可以得到 ConfigurationClassPostProcessor
类,但是这个类我们并没有手动进行注册。
在 AbstractApplicationContext
中有 addBeanFactoryPostProcessor()
可以手动注册
java
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
}
所以肯定是 Spring
在哪个步骤中自己注册了,要想找到在哪里注册的也不难,那就是在 ConfigurationClassPostProcessor
类的 postProcessBeanDefinitionRegistry()
方法中打断点,然后看调用栈,就可以知道 ConfigurationClassPostProcessor
对象是从哪里获取的,不同的上下文设置的方式可能不同,在给出结论之前再看一下我们的主类测试代码
java
@Configuration
@ComponentScan
public class BeanFactoryPostProcessMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanFactoryPostProcessMain.class);
// BeanFactoryPostProcessor 的测试(修改了 ScanComponent 类的 scope 属性)
ScanComponent bean = context.getBean(ScanComponent.class);
System.out.println(bean);
ScanComponent bean2 = context.getBean(ScanComponent.class);
System.out.println(bean2);
RegisterComponent registerComponent = context.getBean(RegisterComponent.class);
registerComponent.sayHello(); // 会打印 "RegisterComponent.sayHello"
}
}
从测试代码中看到上下文对象是 AnnotationConfigApplicationContext
, 所以下面给出的结论也是基于这个上下文对象, 下面代码执行流程使用序号进行标记
java
// new AnnotationConfigApplicationContext(classes)
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this(); // 1
register(componentClasses);
refresh();
}
// AnnotationConfigApplicationContext 类
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this); // 2
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
// AnnotatedBeanDefinitionReader 类
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry)); // 3
}
// AnnotatedBeanDefinitionReader 类
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);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); // 4
}
// AnnotationConfigUtils 类
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null); // 5
}
// AnnotationConfigUtils 类
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
// 省略
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); // 6
}
// 省略
return beanDefs;
}
// AnnotationConfigUtils 类
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition); // 7
return new BeanDefinitionHolder(definition, beanName);
}
// GenericApplicationContext 类
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition); // 8
}
// DefaultListableBeanFactory 类
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 省略
this.beanDefinitionNames.add(beanName); // 9
// 省略
}
至此已经知道 ConfigurationClassPostProcessor
是在何处添加的,而且 ConfigurationClassPostProcessor
类对应的 beanName
是 org.springframework.context.annotation.internalConfigurationAnnotationProcessor