天天看點

Spring源碼分析:實作AOP(轉載)

我的問題

       為了完成公司應用開發平台的設計,這幾天一直在研究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類圖

Spring源碼分析:實作AOP(轉載)

       如以上的類圖所示,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接口,它的相關類圖如下:

Spring源碼分析:實作AOP(轉載)

     實作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

繼續閱讀