Spring 源碼梳理(二) BeanPostProcessor

BeanPostProcessor

1.BeanPostProcessor的概念

BeanPostProcessor是一個接口,它可以使得繼承它的類成爲一個"回調類"(自己起的稱呼),繼承的方法成爲回調函數;它就像Windows中Hook Api ,就是一個鉤子函數,先註冊這個函數,且指定一個事件目標;那麼當一個事件在執行前或者後時,就會觸發這個函數的執行,可以在這個事件的前後做一些操作,影響這個事件。BeanPostProcessor就是這樣的作用,它可以在類的初始化前後改變這個類的屬性,從而影響實體類。

2.下面實際操作這個接口(接着上一篇已定義好的類)

1)調試準備

改變App類,改變後如下:

package com.mycompany.app;

public class 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);
    }
}

新增BeanPostProcessorApp類:

package com.mycompany.app;

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

public class BeanPostProcessorApp implements BeanPostProcessor{

	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		if(bean instanceof App){
			((App)bean).setSays("BeanPostProcessorApp");
		}
		return bean;
	}

	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		return bean;
	}

}

Spring配置文件中增加:

<bean id="beanPostProcessorApp" class="com.mycompany.app.BeanPostProcessorApp"></bean>

新增BeanPostProcessorApp的測試類:

package com.mycompany.app;

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

public class BeanPostProcessorAppTest {

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

}
2)調試如下:

首先進入refresh函數,上一篇已經提到了,這篇主要涉及refresh中的下面兩個方法,registerBeanPostProcessors用來註冊這個Hook函數,finishBeanFactoryInitialization是對配置文件中非延遲加載的bean進行實例化,如下圖:


A:先分析registerBeanPostProcessors這個函數,我們調式進去看一下,首先會進入org.springframework.context.support中的

PostProcessorRegistrationDelegate類,然後到了registerBeanPostProcessors方法,如下圖:


這個方法會把剛纔的BeanPostProcessorApp註冊到beanFactory中,然後我們就會在beanFactory中看到beanPostProcessors多了一個我們自己的BeanPostProcessorApp,下圖所示:


到此,這個鉤子已經註冊完成,當對類進行實例化的時候就會調用該鉤子函數;
B:然後分析finishBeanFactoryInitialization函數,它主要是對bean進行初始化,調用順序如下:

(1).org.springframework.context.support.AbstractApplicationContext中的

(2).org.springframework.beans.factory.support.DefaultListableBeanFactory中的

(3).org.springframework.beans.factory.support.AbstractBeanFactory中的

(4).org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的


(5).org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的


(6).org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的


(7).先進入applyBeanPostProcessorsBeforeInitialization:


由於beanPostProcessor有多個(之前已經看到了,除了我們自己的“BeanPostProcessorApp”,還有幾個暫不知其意,以後遇到再進行分析), 所以會找這些processors的postProcessBeforeInitialization方法實現, 當for循環到我們的processor時,就會執行

我們自己寫的方法:


自己的方法:


到此就完成了我們的目的,對App這個類,進行Hook,而且已經改變了實體類App的says的值。最後當我們進行getBean("app")的操作時,我們進行打印結果如下:

<span style="font-family:SimSun;font-size:18px;"><span style="font-family:Arial Black;">App.app():BeanPostProcessorApp</span></span>
同樣的,After的操作同Before一樣;

注:

上面的bean的初始化,是在讀取配置文件的時候進行的; 如果是延遲加載的情況,是否能夠Hook成功呢。 對於App和BeanPostProcessorApp同時延遲加載或者任意一個延遲加載的情況,先思考,後面再進行分析。

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