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同時延遲加載或者任意一個延遲加載的情況,先思考,後面再進行分析。