BeanFactoryPostProcessor后置处理器
BeanFactoryPostProcessor接口功能
上一篇文章讲解了如何解析配置文件生成BeanDefinition对象,如感性趣,欢迎阅读Spring的IOC容器—BeanFactory—容器加载过程解析,那么获得beanDefinition对象之后,容器下一步值工作是干啥呢?很容易猜出,下一步的任务便是执行BeanFactoryPostProcessor接口中的方法。该接口中只有一个方法,其输入参数为ConfigurableListableBeanFactory,该接口继承了ListableBeanFactory接口。因此,我们可以通过该方法对注册到beanDefinitionRegistry实现类中的beanDefinition对象进行操作。
BeanFactoryPostProcessor接口:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}
下面给出一段代码,展示一下BeanFactoryPostProcessor接口的强大功能
spring.xml文件如下,配置了两个对象,分别为ClassA, MyBeanFactoryPostProcessor
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="classA" class="springBeanTest.ClassA"/>
<bean id="myBeanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor"/>
</beans>
spring2.xml文件如下,配置了一个bean对象classB
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="classB" class="springBeanTest.ClassB"/>
</beans>
PClass源码如下:
public interface PClass {
void say();
}
ClassB源码如下:
public class ClassB implements PClass{
String content = "原始类容";
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public void say(){
System.out.println(content);
}
}
MyBeanFactoryPostProcessor源码如下,在该后置处理器方法中,新注册了ClassB的BeanDefinition对象。
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
BeanDefinition definition = configurableListableBeanFactory.getBeanDefinition("classB");
MutablePropertyValues propertyValues = definition.getPropertyValues();
//设置classB的属性值
propertyValues.add("content", "修改之后的内容");
}
}
测试函数如下:
public class LifeCycleTest {
@Test
public void test1(){
//创建bean的工厂类
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//创建一个xml文件的reader类,将bean工厂传入reader中
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
//加载xml未配置文件,并将配置文件解析成BeanDefinition对象保存在工厂类中
reader.loadBeanDefinitions("classpath:/spring.xml");
BeanFactoryPostProcessor beanFactoryPostProcessor = (BeanFactoryPostProcessor) beanFactory.getBean("myBeanFactoryPostProcessor");
//执行后置处理器方法
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
ClassB classB = (ClassB) beanFactory.getBean("classB");
classB.say();
}
}
结果如下图:
结果如下图:classB答应的内容并不是他的默认内容,而是在后置处理器中修改后的内容。
后置处理器的应用场景
在使用spring框架的时候,在配置数据库的时候,经常使用占位符,并将这些占位符所代表的资源配置在一个专门的文件中。当解析完配置文件之后,开始执行配置的后置处理器方法,因此可以在这个时候,通过后置处理器方法,将BeanDefinition对象中的占位符替换成属性配置文件中的具体属性值。代码如下:
User类:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}
User类:
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
spring.xml配置文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:/dataSource.properties"/>
</bean>
<bean id="user" class="springBeanTest.User">
<property name="username" value="${user.name}"/>
<property name="password" value="${user.password}"/>
</bean>
</beans>
测试类如下:
public class LifeCycleTest {
@Test
public void test1(){
//创建bean的工厂类
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//创建一个xml文件的reader类,将bean工厂传入reader中
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
//加载xml未配置文件,并将配置文件解析成BeanDefinition对象保存在工厂类中
reader.loadBeanDefinitions("classpath:/spring.xml");
BeanDefinition definition = beanFactory.getBeanDefinition("user");
MutablePropertyValues propertyValues = definition.getPropertyValues();
//获取后置处理器方法执行前的属性值
Object username = propertyValues.get("username");
System.out.println(username);
PropertyPlaceholderConfigurer beanFactoryPostProcessor = (PropertyPlaceholderConfigurer) beanFactory.getBean("propertyPlaceholderConfigurer");
//执行后置处理器方法,使用属性值代替占位符
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
User user = (User) beanFactory.getBean("user");
//打印后置处理器方法执行后的属性值
System.out.println(user.getPassword());
}
}
执行结果:
从执行结果可以看出,在使用后置处理器之前,username的属性值为xml文件中的属性配置占位符,执行后置处理器方法后,占位符被替换成properties文件中的相应属性值。
总结:后置处理器方法的作用就是对beanDefinition对象的内容进行修改。当开发中需要修改beanDefinition对象的内容时,可以使用现成的后置处理器,也可以自定义后置处理器,实现BeanFactoryPostProcessor接口,当执行完配置文件的解析工作,得到beanFactory对象之后再调用后置处理器方法即可。