Spring版本
5.2.5.RELEASE
参考
源码解读
我们知道,BeanPostProcessor
是用来改变bean实例的。同样在 Spring 容器启动阶段,Spring 也提供了一种容器扩展机制:BeanFactoryPostProcessor
,该机制作用于容器启动阶段,允许我们在容器实例化 Bean 之前对注册到该容器的 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;
}
从源码注释可以看出,该接口是在standard initialization之后修改容器上下文的内部bean factory,这时候所有的bean definition已经被加载,但是还没初始化任何一个bean。下面通过具体例子来清晰认识一下。
Demo
Student
public class Student {
private String id;
private String name;
private String desc;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
MyBeanFactoryPostProcessor
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("call MyBeanFactoryPostProcessor#postProcessBeanFactory");
BeanDefinition student = beanFactory.getBeanDefinition("student");
student.getPropertyValues().add("name", "name set by custom BeanFactoryPostProcessor");
}
}
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBeanFactoryPostProcessor" class="com.kungyu.custom.element.MyBeanFactoryPostProcessor"/>
<bean id="student" class="com.kungyu.custom.element.Student">
<property name="name" value="name"/>
<property name="id" value="id"/>
</bean>
</bean>
测试
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
结果
可以看到,在
spring.xml
文件中设置的name
属性已经被覆盖。
和
BeanPostProcessor
类似,当我们自定义多个有序的BeanFactoryPostProcessor
的时候,需要实现Ordered
接口重写getOrder
方法定义执行顺序。
思考
回头看前面对于BeanDefinition
的解析文章,发现并不像BeanPostProcessor
那样,在bean实例化过程中调用了BeanPostProcessor
进行增强处理,那么,BeanFactoryPostProcessor
到底是在哪里对BeanDefinition
进行了处理呢?
怀着疑问对心情,开始debug,断点位于MyBeanFactoryPostProcessor#postProcessBeanFactory
中,发现调用栈如下:
可以看到,在
ClassPathXmlApplicationContext
初始化代码中,调用了invokeBeanFactoryPostProcessors
方法:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
这里通过getBeanFactoryPostProcessors
拿到了我们自定义的BeanFactoryPostProcessor
。那么,BeanDefinition
是在哪里加载的呢?查看processBeanDefinition
调用栈如下:
可以看到也是在
ClassPathXmlApplicationContext
初始化中调用的,并且调用的方法obtainFreshBeanFactory
是在invokeBeanFactoryPostProcessors
之前调用的。
总结
一般情况下,我们不会去自定义BeanFactoryPostProcessor
,而是使用spring提供的BeanFactoryPostProcessor
。常用的BeanFactoryPostProcessor
有以下俩个:
-
PropertySourcesPlaceholderConfigurer
,具体可戳《Spring源码解析(十七)-PropertySourcesPlaceholderConfigurer》 -
PropertyOverrideConfigurer
,具体可戳《Spring源码解析(十八)-PropertyOverrideConfigurer》