1. 程式人生 > >【Spring學習24】容器擴充套件點:後置處理器BeanFactoryPostProcessor

【Spring學習24】容器擴充套件點:後置處理器BeanFactoryPostProcessor

上篇說到的BeanPostProcessor(Bean後置處理器)常用在對bean內部的值進行修改;實現Bean的動態代理等。
BeanFactoryPostProcessor和BeanPostProcessor都是spring初始化bean時對外暴露的擴充套件點。但它們有什麼區別呢?
由《理解Bean生命週期》的圖可知:BeanFactoryPostProcessor是生命週期中最早被呼叫的,遠遠早於BeanPostProcessor。它在spring容器載入了bean的定義檔案之後,在bean例項化之前執行的。也就是說,Spring允許BeanFactoryPostProcessor在容器建立bean之前讀取bean配置元資料,並可進行修改。例如增加bean的屬性和值,重新設定bean是否作為自動裝配的侯選者,重設bean的依賴項等等。

在srping配置檔案中可以同時配置多個BeanFactoryPostProcessor,並通過在xml中註冊時設定’order’屬性來控制各個BeanFactoryPostProcessor的執行次序。

BeanFactoryPostProcessor介面定義如下:

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

介面只有一個方法postProcessBeanFactory。該方法的引數是ConfigurableListableBeanFactory型別,實際開發中,我們常使用它的getBeanDefinition()方法獲取某個bean的元資料定義:BeanDefinition。它有這些方法:
這裡寫圖片描述

看個例子:
配置檔案中定義了一個bean:

<bean id="messi" class="twm.spring.LifecycleTest.footballPlayer">
    <property name="name" value="Messi"></property>
    <property name="team" value="Barcelona"></property>
</bean>

建立類beanFactoryPostProcessorImpl,實現介面BeanFactoryPostProcessor:

public class beanFactoryPostProcessorImpl implements BeanFactoryPostProcessor{

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("beanFactoryPostProcessorImpl");
        BeanDefinition bdefine=beanFactory.getBeanDefinition("messi");
        System.out.println(bdefine.getPropertyValues().toString());
        MutablePropertyValues pv =  bdefine.getPropertyValues();  
            if (pv.contains("team")) {
                PropertyValue ppv= pv.getPropertyValue("name");
                TypedStringValue obj=(TypedStringValue)ppv.getValue();
                if(obj.getValue().equals("Messi")){
                    pv.addPropertyValue("team", "阿根延");  
                }
        }  
            bdefine.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    }
}

呼叫類:

public static void main(String[] args) throws Exception {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
    footballPlayer obj = ctx.getBean("messi",footballPlayer.class);
    System.out.println(obj.getTeam());
}

輸出:

PropertyValues: length=2; bean property ‘name’; bean property ‘team’
阿根延

在《PropertyPlaceholderConfigurer應用》提到的PropertyPlaceholderConfigurer這個類就是BeanFactoryPostProcessor介面的一個實現。它會在容器建立bean之前,將類定義中的佔位符(諸如${jdbc.url})用properties檔案對應的內容進行替換。