【小白的Spring源码手册】 BeanFactoryPostProcessor的注册和用法(BFPP)


前言

沿用上一篇文章的流程图,我们的注解类应用上下文中的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

  1. 根据注册方式:手动注册 > 自动注册
  2. 根据注册顺序:先注册 > 后注册
  3. 根据实现类型:BeanDefinitionRegistryPostProcessor > BeanFactoryPostProcessor
  4. 根据排序接口:PriorityOrdered > Ordered > 无排序(无排序时根据注入顺序)
  5. 根据排序序号:Integer.MIN_VALUE > Integer.MAX_VALUE

根据上面的优先级类型,我们排列出一个完整的优先级

出于美观考虑,简化一些写法

  • 把执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法简化为:BDRPP#registry
  • 把执行BeanDefinitionRegistryPostProcessor#postProcessBeanFactory 方法简化为:BDRPP#beanfactory
  • 把执行BeanFactoryPostProcessor#postProcessBeanFactory 方法简化为: BFPP#beanfactory
  1. 手动注册 + BDRPP#registry
  2. 自动注册 + BDRPP#registry+ PriorityOrdered
  3. 自动注册 + BDRPP#registry+ Ordered
  4. 自动注册 + BDRPP#registry+ 无排序
  5. 手动注册 + BDRPP#beanfactory
  6. 手动注册 + BFPP#beanfactory
  7. 自动注册 + BDRPP#beanfactory(根据BDRPP#Registry的执行顺序)
  8. 自动注册 + BFPP#beanfactory
  9. 自动注册 + BFPP#beanfactory
  10. 自动注册 + BFPP#beanfactory+ 无排序

对于BDRPP#registry方法,如果高优先级注册了新的BDRPP定义,那么这个新的BDRPP会在次一级的优先级中执行。比如:在配置类中通过@Bean注入了新的BDRPP,由于配置类后处理器ConfigurationClassPostProcessor的优先级为PriorityOrdered,那么由配置类注入的新BDRPP(PriorityOrdered或Ordered)将在下一级优先级Ordered中执行,无排序类型同理。无排序优先级的内容将会循环执行,直到没有新的BDRPP定义产生。

这一节的内容绕是绕了点,不过如果需要自己实现BFPP的话,那么了解这些是非常有必要的,因为不同优先级的BFPP的作用范围不同,高优先级BFPP将会影响低优先级的表现,或者低优先级会覆盖高优先级的操作。所以如果你的BFPP不起作用的话可以先看看是否受到优先级影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值