Spring 源碼梳理(四) BeanFactoryPostProcessor

BeanFactoryPostProcessor

上篇介紹了BeanPostProcessor(後面以Post代替),這篇講的是BeanFactoryPostProcessor(後面以PostFactory代替),後者也是可以修改Bean的配置。 

1.它們的區別是什麼?不是網上說的“BeanPostProcessor不能夠修改Bean的配置,而BeanFactoryPostProcessor可以”,實際上兩者都是可以,它們的區別實際上是,對Bean的修改的“層面”不同;

做一個這樣的比喻,類Bean是一個模具,實例化後的bean是從模具中出來的模型,PostFactory是作用是修改這個模具,而Post作用是修改放入模具中的產品的原料以及修改從模具中出來的產品的原料。 整個過程就是這樣的,Spring找到Bean模具,PostFactory修改模具,Post先改變原料,然後放入Bean這個模具,產品出來後Post再次修改這個產品。

2.PostFactory如何使用?

我們看一下源代碼:


PostProcessor的註冊位於Bean的加載之後和Post的註冊之前;進入到這個invokeBeanFactoryPostProcessors的內部:


上面的第一個方法getBeanNamesForType查找所有實現BeanFactoryPostProcessor的類,然後通過add方法把這些類加入到無序的List中(其中也有有序List),說明支持BeanFactoryPostProcessor的排序。最後invokeBeanFactoryPostProcessors方法真正執行所有的實現類(nonOrderedPostProcessors);下面實例演示它的用法。

3.在演示之前,對於Post除了前面文章的講述外,還有一個細節:繼續上一篇文章,我們仍然分析下面這個方法doCreateBean


上圖兩個方法都是在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的doCreateBean方法中的,第一個方法執行構造函數,第二個方法如下:


4.到此爲止,執行順序全部清楚了,下面貼上實例:

App.java

package com.mycompany.app;

import org.springframework.beans.factory.InitializingBean;

public class App implements InitializingBean
{
	private App(){
		System.out.println("App.App()");
	}
	private  String says="App";
    public String getSays() {
		return says;
	}
	public void setSays(String says) {
		this.says = says;
	}
	public void say(){
    	System.out.println("App.app():"+says);
    }
	
	/**
	 * 在構造函數和getset方法之後執行postProcessBeforeInitialization方法
	 */
	
	/*這個方法是InitializingBean在繼承InitializingBean接口後,要實現的方法,顧名思義,是在
	 *屬性設置之後進行一些操作*/
	public void afterPropertiesSet() throws Exception {
		System.out.println("App.afterPropertiesSet()");
	}
	/*這個方法是在Spring配置中通過init-method屬性指定爲該方法,然後纔會執行,在afterPropertiesSet方法之後*/
	public void initMethod(){
		System.out.println("App.initMethod()");
	}
	
	/**
	 *在afterPropertiesSet和initMethod方法之後執行postProcessAfterInitialization方法
	 */
	
}

BeanPostProcessorApp.java

package com.mycompany.app;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class BeanPostProcessorApp implements BeanPostProcessor{
	
	/*如果打印結果出現該字符串,證明進行了初始化*/
	private BeanPostProcessorApp(){
		System.out.println("BeanPostProcessorApp.BeanPostProcessorApp()");
	}
	
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		if(bean instanceof App){
			((App)bean).setSays("Before:BeanPostProcessorApp");
			System.out
					.println("BeanPostProcessorApp.postProcessBeforeInitialization()");
		}
		return bean;
	}

	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		if(bean instanceof App){
			((App)bean).setSays("After:BeanPostProcessorApp");
			System.out
					.println("BeanPostProcessorApp.postProcessAfterInitialization()");
		}
		return bean;
	}

}

BeanFactoryPostProcessorApp.java

package com.mycompany.app;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class BeanFactoryPostProcessorApp implements BeanFactoryPostProcessor{
	private BeanFactoryPostProcessorApp() {
		System.out.println("BeanFactoryPostProcessorApp.BeanFactoryPostProcessorApp()");
	}

	public void postProcessBeanFactory(
			ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition beanDefinition = (BeanDefinition)beanFactory.getBeanDefinition("app");
		beanDefinition.setAttribute("says", "BeanFactoryPostProcessor");
		System.out
				.println("BeanFactoryPostProcessorApp.postProcessBeanFactory(): "+beanDefinition.getAttribute("says"));
	}

}

SpringBean.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:context="http://www.springframework.org/schema/context"  
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"  
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd  
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd  
        http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">  
   
      
    <bean id="app" class="com.mycompany.app.App" init-method="initMethod"></bean>  
  
  	<bean id="beanPostProcessorApp" class="com.mycompany.app.BeanPostProcessorApp"></bean>
  	
  	<bean id="beanFactoryPostProcessorApp" class="com.mycompany.app.BeanFactoryPostProcessorApp"></bean>
</beans>

BeanFactoryPostProcessorAppTest.java

package com.mycompany.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanFactoryPostProcessorAppTest {
	public static void main(String[] args) {
    	@SuppressWarnings("resource")
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringBean.xml"); 
        App app = (App)applicationContext.getBean("app");  
        app.say();
	}

}

整體目錄如下(AppTest...等三個文件,內容其實是一樣的):


運行BeanFactoryPostProcessorAppTest.java,結果如下,和上面的分析是一致的:


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