Spring扩展点之BeanFactoryPostProcessor

简介

BeanFactoryPostProcessor只有一个postProcessBeanFactory方法,该方法接收一个参数就是spring容器使用的beanFactory,我们可以自行实现该方法对所有的beanDefinition进行修改,其源码如下:

@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;

}

调用时机

Spring会在所有beanDefinition加载之后,开始实例化bean之前调用BeanFactoryPostProcessor的postProcessBeanFactory方法。

注册方式

要想BeanFactoryPostProcessor的实现类正常工作,首先要将它们注册到Spring容器中。

Spring提供了两种注册方式:

  1. 将它们作为普通的Bean注册到Spring容器中,Spring后续会在PostProcessRegistrationDelegate的invokeBeanFactoryPostProcessors方法中找出所有实现了BeanFactoryPostProcessor的bean
  2. 调用ConfigurableApplicationContext的addBeanFactoryPostProcessor方法注册到Spring中

使用方式

假设我们有一个普通Spring bean:

@Component
public class MyBean {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }
}

实现自己的BeanFactoryPostProcessor,对beanDefinition进行修改:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // spring中默认的bean名称为首字母小写的类名,所以这里的'myBean'就是上面定义的bean
        BeanDefinition myBean = beanFactory.getBeanDefinition("myBean");

        // 设置属性值
        MutablePropertyValues propertyValues = myBean.getPropertyValues();
        propertyValues.addPropertyValue("field", "value");

        // 修改bean的定义
        myBean.setPrimary(true);
    }
}

在MyBeanFactoryPostProcessor的postProcessBeanFactory方法中,我们将MyBean的field属性值设置为’value’,并设置它为primary(效果等同于添加@Primary注解)。

这里我们采用了前面提到的第一种注册方式,将MyBeanFactoryPostProcessor作为一个普通bean注册到Spring容器中,由容器帮我们发现并执行对应方法。

注意事项

不要在BeanFactoryPostProcessor中进行bean的实例化

根据Spring的官方文档,在BeanFactoryPostProcessor中进行bean的实例化可能导致不能预期的副作用,因此如果需要修改bean实例化的过程,请使用BeanPostProcessor。

在BeanFactoryPostProcessor中无法使用@Autowired/@Value注解

Spring在很早的阶段就会开始创建BeanFactoryPostProcessor的实现类并调用其中对应的方法,此时负责处理@Autowired或@Value注解的类还没有创建(它们由BeanPostProcessor的实现类负责处理),因此在BeanFactoryPostProcessor中使用这些注解并不能实现预期的效果。

例如:

@Component
public class AnnotationBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Autowired
    private MyBean myBean;

    @Value("1")
    private String value;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println(myBean); // 输出null
        System.out.println(value); // 输出null
    }
}

多个BeanFactoryPostProcessor的执行顺序

  1. 通过addBeanFactoryPostProcessor方法注册到Spring中的类,执行顺序与它们注册的顺序相同
  2. 实现了PriorityOrdered接口的类,getOrder方法返回值越小越早执行
  3. 实现了Ordered接口的类,getOrder方法返回值越小越早执行
  4. 其他BeanFactoryPostProcessor实现类,执行顺序并没有明确约定

另外,BeanFactoryPostProcessor有个子接口BeanDefinitionRegistryPostProcessor,如果一个类实现的是BeanDefinitionRegistryPostProcessor,那么它会在所有仅实现BeanFactoryPostProcessor类之前执行。多个BeanDefinitionRegistryPostProcessor的执行顺序与前面的1-4点相同。

不要同时使用两种注册方式

前面介绍的两种注册方式如果同时使用会导致postProcessBeanFactory方法被执行两遍,因此如果用addBeanFactoryPostProcessor方法注册的类请确保它们不会作为bean被添加到Spring容器中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值