Spring版本
5.2.5.RELEASE
参考
源码解读
在bean的创建流程中,可以看到诸多BeanPostProcessor
的诸多应用,那么,BeanPostProcessor
究竟是个怎样的神奇的存在呢?
BeanPostProcessor
public interface BeanPostProcessor {
/**
* Apply this {@code BeanPostProcessor} to the given new bean instance <i>before</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* <p>The default implementation returns the given {@code bean} as-is.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* Apply this {@code BeanPostProcessor} to the given new bean instance <i>after</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
* instance and the objects created by the FactoryBean (as of Spring 2.0). The
* post-processor can decide whether to apply to either the FactoryBean or created
* objects or both through corresponding {@code bean instanceof FactoryBean} checks.
* <p>This callback will also be invoked after a short-circuiting triggered by a
* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
* in contrast to all other {@code BeanPostProcessor} callbacks.
* <p>The default implementation returns the given {@code bean} as-is.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.FactoryBean
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
通过源码注释可以看到,postProcessBeforeInitialization
提供了一个途径去修改一个已经实例化的bean,但这个修改是发生在填充属性之后初始化bean之前的,而返回值则可能是一个对原始bean进行过包装后的bean。
与postProcessBeforeInitialization
不同的是,postProcessAfterInitialization
发生在填充属性之后且初始化bean之后。
俩者的不同点在于是否初始化bean,这从方法名上其实也可以看出来,下面,通过demo具体演示一下如何通过BeanPostProcessor
修改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;
}
}
BeanProcessorsTest
public class BeanProcessorsTest implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization");
if (bean instanceof Student) {
((Student) bean).setId("id set by postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization");
if (bean instanceof Student) {
((Student) bean).setName("name set by postProcessAfterInitialization");
}
return bean;
}
}
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="beanProcessorsTest" class="com.kungyu.custom.element.BeanProcessorsTest"/>
<bean id="student" class="com.kungyu.custom.element.Student">
<property name="name" value="name"/>
<property name="id" value="id"/>
</bean>
</beans>
测试
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
BeanProcessorsTest beanProcessorsTest = (BeanProcessorsTest) context.getBean("beanProcessorsTest");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
System.out.println(student.getId());
}
}
结果
可以看到,在spring.xml
文件中设置的id
和name
俩者的初始值已经被覆盖成BeanProcessorsTest
中设置的值