简介
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提供了两种注册方式:
- 将它们作为普通的Bean注册到Spring容器中,Spring后续会在PostProcessRegistrationDelegate的invokeBeanFactoryPostProcessors方法中找出所有实现了BeanFactoryPostProcessor的bean
- 调用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的执行顺序
- 通过addBeanFactoryPostProcessor方法注册到Spring中的类,执行顺序与它们注册的顺序相同
- 实现了PriorityOrdered接口的类,getOrder方法返回值越小越早执行
- 实现了Ordered接口的类,getOrder方法返回值越小越早执行
- 其他BeanFactoryPostProcessor实现类,执行顺序并没有明确约定
另外,BeanFactoryPostProcessor有个子接口BeanDefinitionRegistryPostProcessor,如果一个类实现的是BeanDefinitionRegistryPostProcessor,那么它会在所有仅实现BeanFactoryPostProcessor类之前执行。多个BeanDefinitionRegistryPostProcessor的执行顺序与前面的1-4点相同。
不要同时使用两种注册方式
前面介绍的两种注册方式如果同时使用会导致postProcessBeanFactory方法被执行两遍,因此如果用addBeanFactoryPostProcessor方法注册的类请确保它们不会作为bean被添加到Spring容器中。