我的問題
為了完成公司應用開發平台的設計,這幾天一直在研究spring的擴充機制。spring的核心無疑是beanfactory, applicationcontext和aop。在“spring aop程式設計”教程的例子中,是由proxyfactorybean來實作的。問題來了,普通的bean和factorybean的配置完全是一樣的。那 麼,beanfactory是如何區分普通的bean和用作proxy的factorybean的?proxyfactorybean又是怎樣實作aop 功能的?(本文還很不完善,我會繼續修改。)
factorybean的職責
factorybean在spring中被當成一種特殊的bean,通過實作factorybean接口進行擴充。factorybean的職責是:
l.封裝了建立對象或查找對象的邏輯。
2.提供了一個中間層,用于支援aop。
我們來看一個localstatelesssessionproxyfactorybean的例子。首先,定義stateless ejb的代理,id為ejbserviceproxy:
<bean id="ejbserviceproxy" class="localstatelesssessionproxyfactorybean">
<property name="jndiname">
<value>myejb</value>
</property>
<property name="businessinterface">
<value>com.mycompany.mybusinessinterface</value>
</bean>
然後,再将這個業務邏輯服務對象注入客戶程式:
<bean id="myaction" class = "samples.myaction">
<property name="myservice">
<ref bean="ejbserviceproxy"/>
</property>
</bean>
這樣,客戶程式并不知道myservice的實作細節,spring使用factorybean完成了兩者之間的解耦。
準備代碼分析環境
1. 安裝eclipse和spring ide。
2. 下載下傳spring framework源代碼,并導入eclipse。
3. 在類路徑建立log4j.properties配置檔案,設定如下:
log4j.rootlogger=debug, stdout
log4j.appender.stdout=org.apache.log4j.consoleappender
log4j.appender.stdout.layout=org.apache.log4j.patternlayout
log4j.appender.stdout.layout.conversionpattern=%d{sss} %p %c{2} - %m%n
4. 編寫testcase,跟蹤console視窗的debug資訊。
factorybean源代碼分析
如果bean實作了factorybean接口,beanfactory将把它作為一個bean工廠,而不是直接作為普通的bean。正常情況下, beanfactory的getbean("bean")傳回factorybean生産的bean執行個體,如果要傳回factorybean本身的執行個體, 使用getbean("&bean")的調用方式。
在分析proxyfactorybean之前,我們先分析beanfactory,它是spring framework的基礎。我們看看它是如何分别處理普通的bean和factorybean的。
beanfactory分析
beanfactory類圖

如以上的類圖所示,xmlbeanfactory繼承了abstactbeanfactory抽象類。abstactbeanfactory類中使用了 template method設計模式,其中的模闆方法為getbeandefinition()和createbean()兩個抽象方法。其中 abstractautowirecapablebeanfactory類實作了getbeandefinition()方法, defaultautowirecapablebeanfactory類實作了getbeandefinition()方法。當調用getbean()方 法時,abstractbeanfactory類定義的邏輯分别調用了這兩個模闆方法。
beanfactory類的調用順序
我們暫時不使用applicationcontext,以簡化分析過程。我在這裡使用了“spring aop程式設計”的例子,請參照該教程閱讀。首先,編寫測試用例,代碼如下:
public class aoptest extends testcase {
xmlbeanfactory factory = null;
protected void setup() throws exception {
super.setup();
inputstream is = new fileinputstream("testaop.xml");
factory = new xmlbeanfactory(is);
}
public void testgetbean() {
bean bean = (bean)factory.getbean("bean");
assertnotnull(bean);
bean.themethod();
}
}
1. 首先,xmlbeanfactory使用xmlbeandefinitionreader讀入testaop.xml配置檔案,後者用 xmlbeandefinitionparser和defaultxmlbeandefinitionparser進行分析,從中得到 beandefinition的資訊,并儲存在xmlbeandefinitionreader的beandefinitionregistry變量裡。
2. 客戶程式調用getbean方法時,abstractbeanfactory首先使用transformedbeanname方法分析傳入的bean名稱,判斷客戶程式需要factorybean本身,還是它所建立的bean對象。
3. 接下來,如果bean被定義為singleton模式,abstractbeanfactory調用createbean方法根據 beandefinition資訊執行個體化bean類,然後将該bean執行個體傳給getobjectforsharedinstance方法并傳回 getobjectforsharedinstance的傳回對象。getobjectforsharedinstance方法摘要如類圖所示,首先判斷 bean是否繼承了factorybean。如果是,傳回factorybean的getobject方法(下節我将詳細分析使用 proxyfactorybean如何實作aop);如果不是,傳回bean對象。
4. 如果bean被定義為prototype模式,每次客戶程式請求都會生成新的bean執行個體,是以,createbean方法直接執行個體化bean對象并傳回。
proxyfactorybean如何實作aop
proxyfactorybean類圖
factorybean接口如下圖所示,共有三個方法getobject,getobjecttype,和issingleton。proxyfactorybean實作了factorybean接口,它的相關類圖如下:

實作aop的過程
如上圖所示,proxyfactorybean類繼承了advisedsupport類,後者繼承了proxyconfig類并定義了操作advisor 和interceptor的接口,以支援aop。當beanfactory執行個體化proxyfactorybean時,根據配置檔案的定義将關于 advice,pointcut,advisor,所代理的接口和接口實作類的所有資訊傳給proxyfactorybean。
當客戶程式調用beanfactory的getbean方法時,proxyfactory使用jdkdynamicaopproxy執行個體化 beanimpl類,并用jdkdynamicaopproxy的invoke方法執行advice。至于執行advice的時機,由 proxyfactorybean調用regexpmethodpointcutadvisor進行判斷。
文章轉自莊周夢蝶 ,原文釋出時間5.17