Spring原理解析-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对象之后再调用后置处理器方法即可。

发布了3 篇原创文章 · 获赞 5 · 访问量 123

猜你喜欢

转载自blog.csdn.net/ranxiaochuan1994/article/details/105242341