目录
- 前言
- 应用
- 1. 手动注册
- 2. 自动注册
- 3. 优先级
前言
沿用上一篇文章的流程图,我们的注解类应用上下文中的AnnotationConfigApplicationContext#scan(String...)
方法已经将所有BeanDefinition注册到了IoC容器中。完成注册后,开始执行AbstractApplicationContext#refresh()
方法,这个方法中Spring向外部提供了几个非常重要的扩展点:BeanFactoryPostProcessor、BeanPostProcessor。他们的作用如下:
BeanFactoryPostProcessor
:简称BFPP,用于管理BeanDefinition,甚至是管理整个IoC容器,常见业务实现有指定限定符(@Qualifier)、占位符替换(@Value)、配置类注册定义(@Configuration)等等;BeanPostProcessor
:简称BPP,用于管理Bean生命周期,常见业务实现有初始化(@PostConstruct)、注入依赖(@Autowired)、代理与包装Bean对象、注册事件监听器 、销毁(@PreDestroy)、以及其它生命周期内事件处理等等。
学习和理解这两类处理器,能让你了解很多业务中常用功能的实现原理,看过之后就会恍然大悟,哦!原来我们日常业务使用的注解原来是这么回事。
是后处理器,还是后置处理器?Post Processor直译过来就是后处理器或者后置处理器的意思,两者意思大致相同,网上两个词也都在用。虽然这些处理器接口也并未声明它属于某些行为的后置处理器;也没有相对应的前置处理器(PreProcessor),但就总体流程和接口中方法的注释来看,BeanFactoryPostProcessor#postProcessBeanFactory就是IoC容器初始化流程的后置处理器,用来处理容器初始化后的事件;BeanPostProcessor#postProcessBeforeInitialization、BeanPostProcessor#postProcessAfterInitialization这两个方法则是Bean生命周期(BeanPostProcessor有很多实现类,用于分别处理各个阶段)中初始化前后的后置处理器,关于Bean生命周期后面会发文专门学习探讨一下。
综合来看,怎么称呼都没问题,不过我会在下文中都用后处理器来称呼。
其它Spring源码文章:
Bean的扫描、装配和注册,面试学习可用
BeanFactory后处理器的注册与执行——BeanFactoryPostProcessor(BFPP)
Bean后处理器的注册与执行——BeanPostProcessor(BPP)
应用
关于BFPP的类型:
BeanFactoryPostProcessor:提供
postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
方法,在IoC容器标准初始化完成后,修改IoC容器内容,支持修改Bean定义、允许覆盖或添加属性。
BeanDefinitionRegistryPostProcessor:是BeanFactoryPostProcessor的子类,添加了一个新方法postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
,这个方法则更强调在IoC容器标准初始化完成后,执行postProcessBeanFactory方法之前,注册额外的Bean定义,这些新注册的内容同样会受postProcessBeanFactory方法影响。
1. 手动注册
所有实现BeanFactoryPostProcessor类的BFPP,都可以在上下文容器执行refresh
方法前,通过AbstractApplicationContext#addBeanFactoryPostProcessor
方法手动注册。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.addBeanFactoryPostProcessor(new BfppA());
ctx.addBeanFactoryPostProcessor(new BfppB());
// 手动注册需确保注册必须在执行refresh方法前注册
ctx.refresh();
手动注册的方式在Spring Boot启动类中比较常见,很多功能都是通过手动注册BFPP的方式来实现的。对Spring Boot感兴趣的,可以去看看SpringBoot的启动类(org.springframework.boot.SpringApplication
),它在初始化应用上下文时,添加了很多默认的BFPP类。
// org.springframework.boot.SpringApplication#prepareContext
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
2. 自动注册
也可以通过添加组件注解(如@Component)由IoC容器来自动注册后处理器,Spring会自动管理已经注册的所有BFPP类。
实现自动注册也很简单,添加组件注解即可:
@Component
public class SimpleBfPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注册BeanDefinition等相关内容
RootBeanDefinition rbd = new RootBeanDefinition(ConfigBeanServiceImpl.class);
registry.registerBeanDefinition("beanName", rbd);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 修改beanFactory内容,一般用于修改BeanDefinition的内容
String propertyName = "name";
BeanDefinition bd = beanFactory.getBeanDefinition("beanName");
MutablePropertyValues propertyValues = bd.getPropertyValues();
if (!propertyValues.contains(propertyName)) {
propertyValues.add(propertyName, "BeanFactoryPostProcessor-Property-Value");
}
}
@Override
public int getOrder() {
// 执行的优先级序号
return Ordered.LOWEST_PRECEDENCE;
}
}
在配置类中注入Bean和组件注解的作用相同:
@Configuration
public class PostProcessorConfig {
@Bean
public static SimpleBfPostProcessor simpleBfPostProcessor() {
return new SimpleBfPostProcessor();
}
}
有趣的是,配置类
@Configuration
的扫描和注册Bean的功能就是通过BeanDefinitionRegistryPostProcessor来实现的。所以你可以在配置类中使用@Bean
、@ComponentScans
等等注解来实现注册Bean定义的功能。相关实现可以参考org.springframework.context.annotation.ConfigurationClassPostProcessor
源码。
3. 优先级
看过源码的都会注意到,BFPP其实是有执行优先级的,根据源码,我把优先级分为如下几种类型:
提示:
interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
interface PriorityOrdered extends Ordered
- 根据注册方式:手动注册 > 自动注册
- 根据注册顺序:先注册 > 后注册
- 根据实现类型:BeanDefinitionRegistryPostProcessor > BeanFactoryPostProcessor
- 根据排序接口:PriorityOrdered > Ordered > 无排序(无排序时根据注入顺序)
- 根据排序序号:Integer.MIN_VALUE > Integer.MAX_VALUE
根据上面的优先级类型,我们排列出一个完整的优先级:
出于美观考虑,简化一些写法:
- 把执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法简化为:BDRPP#registry
- 把执行BeanDefinitionRegistryPostProcessor#postProcessBeanFactory 方法简化为:BDRPP#beanfactory
- 把执行BeanFactoryPostProcessor#postProcessBeanFactory 方法简化为: BFPP#beanfactory
- 手动注册 + BDRPP#registry
- 自动注册 + BDRPP#registry+ PriorityOrdered
- 自动注册 + BDRPP#registry+ Ordered
- 自动注册 + BDRPP#registry+ 无排序
- 手动注册 + BDRPP#beanfactory
- 手动注册 + BFPP#beanfactory
- 自动注册 + BDRPP#beanfactory(根据BDRPP#Registry的执行顺序)
- 自动注册 + BFPP#beanfactory
- 自动注册 + BFPP#beanfactory
- 自动注册 + BFPP#beanfactory+ 无排序
对于BDRPP#registry方法,如果高优先级注册了新的BDRPP定义,那么这个新的BDRPP会在次一级的优先级中执行。比如:在配置类中通过@Bean注入了新的BDRPP,由于配置类后处理器ConfigurationClassPostProcessor的优先级为PriorityOrdered,那么由配置类注入的新BDRPP(PriorityOrdered或Ordered)将在下一级优先级Ordered中执行,无排序类型同理。无排序优先级的内容将会循环执行,直到没有新的BDRPP定义产生。
这一节的内容绕是绕了点,不过如果需要自己实现BFPP的话,那么了解这些是非常有必要的,因为不同优先级的BFPP的作用范围不同,高优先级BFPP将会影响低优先级的表现,或者低优先级会覆盖高优先级的操作。所以如果你的BFPP不起作用的话可以先看看是否受到优先级影响。