【spring系列】BeanFactoryPostProcessor和BeanPostProcessor接口

前言

這兩個接口都是spring初始化bean的擴展。允許用戶在bean生成的前後進行特殊處理。

BeanFactoryPostProcessor接口是在IOC容器初始化生成BeanDefinition之後可以對BeanDefinition中的數據進行修改。

BeanPostProcessor接口是允許bean在初始化前後做處理。

注:BeanPostProcessor的所有處理在BeanFactoryPostProcessor之後。

場景

比如一般在配置文件中配置的數據庫密碼都是加密處理的,然後在程序中進行解密,這種操作一般是繼承PropertyPlaceholderConfigurer 類,並且重寫了processProperties方法

在這裏插入圖片描述

可見PropertyPlaceholderConfigurer是實現了BeanFactoryPostProcessor接口做到在bean初始化之前修改了屬性值。

另外xml中配置的屬性值經常會有${jdbc.driver} ,這種配置也可以通過此接口進行屬性的替換。

	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<!-- 配置連接池屬性 -->
		<property name="driverClass" value="${jdbc.driver}" />
		<property name="jdbcUrl" value="${jdbc.url}" />
		<property name="user" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

代碼示例

1.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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userInfo" class="com.example.model.UserInfo" init-method="init"  >
        <property name="name" value="aa"></property>
    </bean>
    <!-- 實現了BeanFactoryPostProcessor接口-->
    <bean id="testBeanFactoryPostProcessor" class="com.example.model.TestBeanFactoryPostProcessor"/>

</beans>

TestBeanFactoryPostProcessor.java

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("***********BeanFactoryPostProcessor***********");
    }
}

Test.java

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring.xml");
        UserInfo userinfo = (UserInfo)context.getBean("userInfo");
        System.out.println(userinfo.getName());
    }

輸出:

BeanFactoryPostProcessor
21:42:53.923 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘userInfo’
這裏是 UserInfo init
aa

2.BeanPostProcessor示例

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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userInfo" class="com.example.model.UserInfo">
        <property name="name" value="aa"></property>
    </bean>
    <!--此實現BeanPostProcessor接口-->
    <bean id="testBeanPostProcessor" class="com.example.model.TestBeanPostProcessor"/>
</beans>

UserInfo.java

InitializingBean.afterPropertiesSet會在bean實例化之後執行。類似於在配置文件中配置init-method

public class UserInfo implements InitializingBean  {

    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("這裏是 UserInfo init");
    }
}

TestBeanPostProcessor.java

public class TestBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(" BeanPostProcessor,在bean生成之前處理 beanName:"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(" BeanPostProcessor,在bean生成之後處理 beanName:"+beanName);
        return bean;
    }
}

Test.java

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring.xml");
        UserInfo userinfo = (UserInfo)context.getBean("userInfo");
        System.out.println(userinfo.getName());
    }

輸出:

21:13:02.042 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@532760d8
21:13:02.449 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [spring.xml]
21:13:02.508 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘testBeanPostProcessor’
21:13:02.567 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘userInfo’
BeanPostProcessor,在bean生成之前處理 beanName:userInfo
這裏是 UserInfo init
BeanPostProcessor,在bean生成之後處理 beanName:userInfo
aa

3.兩個接口對比

配置文件中同樣加載bean

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userInfo" class="com.example.model.UserInfo" init-method="init"  >
        <property name="name" value="aa"></property>
    </bean>
    <bean id="testBeanPostProcessor" class="com.example.model.TestBeanPostProcessor"/>
    <bean id="testBeanFactoryPostProcessor" class="com.example.model.TestBeanFactoryPostProcessor"/>

</beans>
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("***********BeanFactoryPostProcessor***********");
    }
}
public class TestBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(" BeanPostProcessor,在bean生成之前處理 beanName:"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(" BeanPostProcessor,在bean生成之後處理 beanName:"+beanName);
        return bean;
    }
}

執行Test.java之後

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring.xml");
        UserInfo userinfo = (UserInfo)context.getBean("userInfo");
        System.out.println(userinfo.getName());
    }

輸出:

BeanFactoryPostProcessor
21:45:22.435 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘testBeanPostProcessor’
21:45:22.439 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘userInfo’
BeanPostProcessor,在bean生成之前處理 beanName:userInfo
這裏是 UserInfo init
BeanPostProcessor,在bean生成之後處理 beanName:userInfo
aa

ork.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘userInfo’

BeanPostProcessor,在bean生成之前處理 beanName:userInfo
這裏是 UserInfo init
BeanPostProcessor,在bean生成之後處理 beanName:userInfo
aa

​ BeanFactoryPostProcessor的處理在BeanPostProcessor之前。另外BeanFactoryPostProcessor可以對BeanDefinition等進行處理,但是BeanPostProcessor就有侷限性,只能對bean進行處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章