乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Java平臺(tái)AOP技術(shù)研究

       軟件團(tuán)隊(duì)頭目 2008-01-13

      張逸:晴窗筆記

      Java平臺(tái)AOP技術(shù)研究

      1、引言

      2、AOP技術(shù)基礎(chǔ)

      3、Java平臺(tái)AOP技術(shù)研究

      4、.Net平臺(tái)AOP技術(shù)研究

      3.1 Java平臺(tái)AOP技術(shù)概覽

      3.1.1 AOP技術(shù)在Java平臺(tái)中的應(yīng)用

      AOP在實(shí)驗(yàn)室應(yīng)用和商業(yè)應(yīng)用上,Java平臺(tái)始終走在前面。從最初也是目前最成熟的AOP工具——AspectJ,到目前已經(jīng)融和在企業(yè)級(jí)容器JBoss中的JBoss AOP,均建立在Java平臺(tái)上。

      前面已經(jīng)描述到,AOP的目的就是將核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)分離,實(shí)際上這就是一種分散關(guān)注(seperation of concerns)的思路。在Java平臺(tái)下,如果要開發(fā)企業(yè)級(jí)的應(yīng)用,非J2EE莫屬。一個(gè)J2EE應(yīng)用系統(tǒng)只有部署在J2EE容器中才能運(yùn)行,那么為什么要?jiǎng)澐譃镴2EE容器和J2EE應(yīng)用系統(tǒng)? 通過(guò)對(duì)J2EE容器運(yùn)行機(jī)制的分析,我們發(fā)現(xiàn):實(shí)際上J2EE容器分離了一般應(yīng)用系統(tǒng)的一些通用功能,例如事務(wù)機(jī)制、安全機(jī)制以及對(duì)象池或線程池等性能優(yōu)化機(jī)制。這些功能機(jī)制是每個(gè)應(yīng)用系統(tǒng)幾乎都需要的,因此可以從具體應(yīng)用系統(tǒng)中分離出來(lái),形成一個(gè)通用的框架平臺(tái),而且,這些功能機(jī)制的設(shè)計(jì)開發(fā)有一定難度,同時(shí)運(yùn)行的穩(wěn)定性和快速性都非常重要,必須經(jīng)過(guò)長(zhǎng)時(shí)間調(diào)試和運(yùn)行經(jīng)驗(yàn)積累而成,因此,形成了專門的J2EE容器服務(wù)器產(chǎn)品,如Tomcat JBoss、Websphere、WebLogic等。

      從J2EE將應(yīng)用系統(tǒng)和容器分離的策略,我們能夠看到AOP的影子。J2EE應(yīng)用系統(tǒng)就相當(dāng)于AOP技術(shù)中的核心關(guān)注點(diǎn),它的內(nèi)容主要包括企業(yè)系統(tǒng)的商業(yè)邏輯;而J2EE容器則類似于橫切關(guān)注點(diǎn),實(shí)現(xiàn)的是通用的功能機(jī)制。不過(guò)業(yè)界在選擇J2EE容器時(shí),對(duì)于EJB這種重量級(jí)容器服務(wù)器而言,雖然欣賞其高效、穩(wěn)定及企業(yè)級(jí)的容器服務(wù),但對(duì)于整個(gè)容器的高開銷、高成本以及過(guò)于復(fù)雜的解決方案均深懷戒心。因此,隨著J2EE的逐步演化,“輕量級(jí)容器架構(gòu)”通過(guò)開源社區(qū)如激流一般的驅(qū)動(dòng)力,逐漸占據(jù)了J2EE技術(shù)的強(qiáng)勢(shì)地位。而所謂“輕量級(jí)容器”與EJB提供的重量級(jí)架構(gòu)的區(qū)別,就在于借助了AOP技術(shù)和IoC(Inversion of Control,反轉(zhuǎn)模式)機(jī)制,降低了代碼對(duì)于專用接口的依賴性,以簡(jiǎn)短、輕便、專注、可移植的方式實(shí)現(xiàn)業(yè)務(wù)對(duì)象。事實(shí)上,我們看到的美好前景是,如果所有企業(yè)級(jí)服務(wù)都可以通過(guò)AOP機(jī)制提供給普通Java對(duì)象,那么深盔重鎧的應(yīng)用服務(wù)器就不再有存在的價(jià)值了。

      正是看到了AOP技術(shù)在企業(yè)級(jí)開發(fā)中的巨大潛力,而“輕量級(jí)容器”也喚起了改革EJB容器的呼聲(事實(shí)上,最新的 EJB V3.0 標(biāo)準(zhǔn)就使用了輕量級(jí)容器模型),越來(lái)越多的AOP工具在Java平臺(tái)下應(yīng)運(yùn)而生,從而形成了目前AOP工具百家爭(zhēng)鳴的局面。其中,應(yīng)用最為廣泛的主要包括AspectJ、Spring AOP和JBoss AOP等。

      3.1.2 Java平臺(tái)下AOP工具的比較

      AOP是一項(xiàng)新技術(shù),而在Java平臺(tái)下實(shí)現(xiàn)該技術(shù)的工具也非常多。雖然AOP的技術(shù)要素從本質(zhì)上來(lái)講是一致的,但各種工具的實(shí)現(xiàn)方法也各有不同,本節(jié)基于AOP的技術(shù)要素,對(duì)當(dāng)前應(yīng)用較廣泛的AspectJ、Spring AOP和JBoss AOP進(jìn)行比較。

      3.1.2.1 AOP實(shí)現(xiàn)機(jī)制的區(qū)別

      同樣是實(shí)現(xiàn)AOP,且AOP的技術(shù)要素完全相同,但各種AOP工具對(duì)于AOP實(shí)現(xiàn)的底層機(jī)制卻是不盡相同的。

      AspectJ采用了源代碼生成技術(shù)來(lái)實(shí)現(xiàn)AOP。它提供了一套獨(dú)有的基于Java平臺(tái)的AOP語(yǔ)法,以及專有的AspectJ編譯器。編譯器在編譯具有AspectJ語(yǔ)法的Java程序時(shí),能夠識(shí)別諸如aspect,pointcut等特殊關(guān)鍵字,然后利用靜態(tài)織入的方式,修改需要被截取的方法所屬類的源代碼,把a(bǔ)dvice或者introduce的業(yè)務(wù)邏輯代碼注入到正確的位置。利用AspectJ,可以將核心關(guān)注點(diǎn)完全獨(dú)立出來(lái),然后通過(guò)AspectJ語(yǔ)法,編寫符合核心關(guān)注點(diǎn)要求的橫切關(guān)注點(diǎn)代碼,最后通過(guò)AspectJ編譯器,將這兩者在后期結(jié)合起來(lái)。采用這種靜態(tài)織入技術(shù),使得運(yùn)用了AOP技術(shù)的系統(tǒng)在運(yùn)行性能上未受到任何損失,因?yàn)樗鼪]有利用反射技術(shù)或代理技術(shù),而僅僅是程序的靜態(tài)擴(kuò)展而已。然而這種源代碼生成方式實(shí)現(xiàn)的AOP雖然在性能上具備一定的優(yōu)勢(shì),但它同時(shí)會(huì)給開發(fā)帶來(lái)一定的問(wèn)題。例如代碼的后期修改會(huì)給系統(tǒng)帶來(lái)不可估量的影響。

      Spring AOP是Spring框架中的一部分,但可以作為一個(gè)獨(dú)立的模塊單獨(dú)存在。Spring AOP實(shí)現(xiàn)AOP技術(shù)從本質(zhì)上來(lái)講,是利用了JDK提供的動(dòng)態(tài)代理技術(shù)。而從實(shí)際的實(shí)現(xiàn)方式來(lái)看,則是利用了IoC(Inversion of Control,反轉(zhuǎn)模式)機(jī)制,同時(shí)采用了AOP聯(lián)盟(AOP Alliance)的通用AOP接口。首先,Spring AOP通過(guò)xml配置文件配置了pointcut,并利用Interceptor(攔截機(jī))作為設(shè)定的觸發(fā)條件。Interceptor是由用戶自定義的,它相當(dāng)于是AOP中的advice,但該Interceptor需要實(shí)現(xiàn)AOP聯(lián)盟的通用AOP接口,例如org.aopalliance.intercept.MethodInterceptor。最后定義一個(gè)Spring AOP ProxyFactory用于加載執(zhí)行AOP組件,并利用IoC機(jī)制將advice注入到接口以及實(shí)現(xiàn)類中。

      JBoss 4.0提供了AOP框架。與Spring一樣,這個(gè)框架可與JBoss應(yīng)用服務(wù)器緊密結(jié)合,也可以單獨(dú)運(yùn)行在自己的應(yīng)用中。JBoss AOP同樣需要Interceptor攔截器來(lái)完成對(duì)方法的攔截,它要求所有的Interceptor都必須實(shí)現(xiàn)org.jboss.aop.Interceptor接口。在這個(gè)接口中最重要的方法就是invoke()。該方法對(duì)元數(shù)據(jù)直接進(jìn)行操作,并利用反射的原理去攔截方法的消息。Interceptor相當(dāng)于AOP的advice,至于pointcut,則在xml配置文件中配置。可以看出,Spring AOP和JBoss AOP在實(shí)現(xiàn)上屬于動(dòng)態(tài)織入的方式,它們與AspectJ在實(shí)現(xiàn)上是迥然不同的兩種方式。

      3.1.2.2 關(guān)于“Aspect(方面)”的區(qū)別

      在對(duì)aspect的聲明上,可以使用類似Java的代碼,注釋或xml。考慮一個(gè)常用的例子,對(duì)Account類的授權(quán)策略,如果以AOP技術(shù)來(lái)實(shí)現(xiàn),運(yùn)用不同的AOP工具,它們?cè)诜矫媛暶骷夹g(shù)上的差異,是顯而易見的。

      Aspect 中的方面聲明類似于 Java 語(yǔ)言中的類聲明,如圖3.1 所示。

      aop3.1.gif
      圖3.1 AspectJ中的方面聲明

      由于 AspectJ 是 Java 語(yǔ)言語(yǔ)法和語(yǔ)義的擴(kuò)展,所以它提供了自己的一套處理方面的關(guān)鍵字。除了包含字段和方法之外,AspectJ 的方面聲明還包含pointcut和advice成員。示例中的pointcut使用了修飾符(modifier)和通配符(wildcard)模式來(lái)表達(dá)“所有公共方法”。對(duì)帳戶的訪問(wèn),由 pointcut 參數(shù)提供。advice使用這個(gè)參數(shù),而pointcut則用 this(account) 把它綁定。這樣做的效果,就是捕獲了正在執(zhí)行的方法所隸屬的Account對(duì)象。否則,advice的主體與方法的主體相似。advice可以包含認(rèn)證代碼,或者就像在這個(gè)示例中一樣,可以調(diào)用其他方法。

      JBoss AOP 基于 XML 的風(fēng)格來(lái)聲明方面,如圖 3.2 所示。

      aop3.2.gif
      圖3.2 JBoss AOP的方面聲明

      在 XML 風(fēng)格中,aspect、pointcut和advice的聲明都以 XML 形式表示的。advice的實(shí)現(xiàn),用的是普通的 Java 方法,由JBoss AOP框架調(diào)用。pointcut和pointcut到advice的綁定都在方面中用XML注釋聲明。JBoss 沒有顯式地綁定 Account 參數(shù),而是提供了對(duì)當(dāng)前正在執(zhí)行的對(duì)象的反射訪問(wèn),因此需要把類型轉(zhuǎn)換到對(duì)應(yīng)的類型。JBoss AOP還可以通過(guò)標(biāo)簽的方式對(duì)方面進(jìn)行聲明。標(biāo)簽均以“@”字符開始,它的使用有點(diǎn)類似于.Net中的Attribute。

      Spring AOP同樣是基于 XML 的風(fēng)格來(lái)聲明方面,如圖3.3所示。

      aop3.3.gif
      圖3.3 Spring AOP的方面聲明

      與JBoss AOP類似,Spring的advice實(shí)現(xiàn)是帶有特殊參數(shù)的Java方法,由 Spring 框架調(diào)用。XML描述accountBean,Spring框架通過(guò)它訪問(wèn) Account 對(duì)象,包括通知使用的攔截器 advisor 及其匹配模式,還有應(yīng)用到模式的向前(before) 通知。

      由于Spring AOP利用了IoC機(jī)制,因此比較JBoss AOP而言,在xml配置文件中提供了更加精細(xì)的配置。而構(gòu)建、運(yùn)行和配置 Spring AOP 方面的過(guò)程則與JBoss AOP基本相同,不過(guò)Spring AOP依賴的是Spring框架方便的、最小化的運(yùn)行時(shí)配置,所以不需要獨(dú)立的啟動(dòng)器。

      3.1.2.3 語(yǔ)言機(jī)制的區(qū)別

          由于實(shí)現(xiàn)機(jī)制和語(yǔ)法風(fēng)格的不同,三種AOP工具在語(yǔ)言機(jī)制上也有很大的不同,以下從四個(gè)方面來(lái)描述AspectJ、JBossAOP和Spring AOP之間的區(qū)別。

      (1)pointcut匹配和復(fù)合:AspectJ和 JBoss AOP 提供了類似的類型模式支持。它們都允許簽名方面的匹配,對(duì)于 Java 5 應(yīng)用程序來(lái)說(shuō),這些匹配包括注釋和泛型。AspectJ提供了一種簡(jiǎn)潔的引用多個(gè)類型的技術(shù)(例如 Account+ 表示帳戶的所有子類型)。所有的工具都支持通配符匹配。Spring AOP 還提供了對(duì)正則表達(dá)式的支持。雖然這看起來(lái)可能是一個(gè)強(qiáng)大的優(yōu)勢(shì),但還是要指出其他技術(shù)已經(jīng)選擇了放棄正則表達(dá)式,好讓pointcut讀起來(lái)不是太難,同時(shí)不會(huì)存在潛在的損害。pointcut復(fù)合操作符基本上都是相同的。Spring AOP 不提供“非”操作,這個(gè)操作通常與沒有在 Spring AOP 連接點(diǎn)模型的容器(containment)連接點(diǎn)結(jié)合使用。

      (2)advice形式:AspectJ 支持比其他技術(shù)更多的advice形式,而 JBoss AOP 只支持一種advice形式。每種通知形式都可以表達(dá)成 around advice,所以 JBoss 的技術(shù)是無(wú)限的,而且它確實(shí)提供了額外的簡(jiǎn)單性。不好的一面是它損失了簡(jiǎn)潔性。另外,強(qiáng)迫advice去遵守普通的 Java 規(guī)則(就像注釋和 XML 風(fēng)格做的那樣),在一些情況下容易出問(wèn)題,因?yàn)檫@些規(guī)則是為方法設(shè)計(jì)的。AspectJ 擁有把被通知方法的異常“軟化”的能力,這很有用,但是不符合方法異常檢測(cè)的標(biāo)準(zhǔn)語(yǔ)義。

      (3)join point上下文:在 AspectJ中,通過(guò)指定和綁定pointcut參數(shù)訪問(wèn)動(dòng)態(tài)連接點(diǎn)的狀態(tài),類似于在 Java 語(yǔ)言中聲明方法參數(shù)的技術(shù)(請(qǐng)參閱圖3.1)。這為連接點(diǎn)上下文提供了靜態(tài)類型化的好處。JBoss AOP 和 Spring AOP 反射性地訪問(wèn)連接點(diǎn)的狀態(tài),這消除了在切入點(diǎn)表達(dá)式中參數(shù)綁定的復(fù)雜性,代價(jià)是參數(shù)靜態(tài)類型化。Java 程序員習(xí)慣了方法參數(shù)靜態(tài)類型化帶來(lái)的好處,同時(shí)還可以從pointcut參數(shù)的靜態(tài)類型化得到同樣的好處。所以,在 JBoss AOP 最近的發(fā)行版本中,有提供靜態(tài)類型化的“args”的計(jì)劃。

      (4)擴(kuò)展性:aspect的擴(kuò)展性支持庫(kù)方面的部署,這樣可以在日后為特定程序?qū)⑦@些庫(kù)方面具體化。例如,一個(gè)方面庫(kù)可以提供應(yīng)用程序監(jiān)視需要的全部邏輯和基礎(chǔ)設(shè)施。但是,要采用某個(gè)特定項(xiàng)目的庫(kù),那么庫(kù)使用的pointcut必須擴(kuò)展成應(yīng)用程序特定的join point。AspectJ 用抽象方面支持?jǐn)U展性,抽象方面包含抽象的pointcut和具體的advice。擴(kuò)展抽象方面的子方面必須具體化pointcut。JBoss AOP 使用了完全不同的技術(shù),沒有使用抽象切入點(diǎn)機(jī)制。擴(kuò)展是通過(guò)生成aspect的子類、并在 XML 中或通過(guò)注釋定義新的advice綁定而實(shí)現(xiàn)的。pointcut到advice的顯式綁定為JBoss AOP提供了顯著優(yōu)勢(shì),從而可以很容易地把方面擴(kuò)展到新系統(tǒng),無(wú)需要生成子類。

      3.2 Java平臺(tái)下AOP主流工具研究

      3.2.1 AsepctJ研究

      AspectJ作為Java編程語(yǔ)言擴(kuò)展的AOP工具,使得我們運(yùn)用AOP技術(shù)能夠像普通的Java編程那樣,特殊之處,僅在于我們需要使用AspectJ提供的特殊語(yǔ)法。接下來(lái),我將通過(guò)一些實(shí)例,介紹如何運(yùn)用AspectJ實(shí)現(xiàn)AOP技術(shù)。

      3.2.1.1 AspectJ語(yǔ)言特性

      設(shè)定我們的開發(fā)項(xiàng)目中需要應(yīng)用到日志記錄,根據(jù)前面介紹的AOP知識(shí),我們已經(jīng)能夠從這個(gè)需求中識(shí)別出橫切關(guān)注點(diǎn)——日志記錄。因此,我們需要定義關(guān)于“日志記錄”的aspect:

      public aspect AutoLog

          pointcut publicMethods() : execution(public * org.apache.cactus..*(..));
          pointcut logObjectCalls() : execution(* Logger.*(..));
          pointcut loggableCalls() : publicMethods() && ! logObjectCalls(); 

          before() : loggableCalls()
          {
            Logger.entry(thisJoinPoint.getSignature().toString());
          }
          after() : loggableCalls()
          {
            Logger.exit(thisJoinPoint.getSignature().toString());
          }
      }

      如果僅僅熟悉Java編程,會(huì)發(fā)現(xiàn)有很多關(guān)鍵字是Java語(yǔ)言中不曾包含的,它們均是AspectJ提供的。

      分析上述的代碼,首先是aspect的聲明,它類似于Java中的類聲明,定義了一個(gè)aspect:AutoLog。在這個(gè)方面中分別包含了pointcut和advice。

      pointcut共有三個(gè):publicMethod、logObjectCalls和loggableCalls。publicMethod將選擇org.apache.cactus包中的所有公共(public)方法的執(zhí)行。所謂“選擇”,就意味著它的join point為其選擇的方法。當(dāng)這些方法被調(diào)用時(shí),就會(huì)執(zhí)行pointcut的advice代碼。而在pointcut中,execution 是一個(gè)原始的 Pointcut(就象 int 是一種原始的 Java 類型)。它選擇與括號(hào)中定義的方法說(shuō)明匹配的任何方法的執(zhí)行。方法說(shuō)明允許包含通配符。logObjectCalls的pointcut則選擇Logger 類中的所有方法的執(zhí)行。第三個(gè)pointcut比較特殊,它使用&& !合并了前兩個(gè) Pointcut,這意味著它選者了除Logger類中的公共方法以外, org.apache.cactus 中所有的公共方法。

      advice在aspect中,被用來(lái)完成實(shí)際的日志紀(jì)錄。advice有三種,分別為before、after和around。如上述代碼中定義的advice:
      before() : loggableCalls()
      {
          Logger.entry(thisJoinPoint.getSignature().toString());
      }

      該advice的定義表示的含義是,如果org.apache.cactus中所有的公共方法(Logger類的公共方法除外)被執(zhí)行,則在這些方法執(zhí)行之前,需要先執(zhí)行該advice定義的邏輯。

      3.2.1.2 AspectJ的高級(jí)語(yǔ)言特性

      在本文第二部分介紹AOP技術(shù)時(shí),提到了橫切技術(shù)的分類。其中,靜態(tài)橫切技術(shù)能夠擴(kuò)展一個(gè)對(duì)象的結(jié)構(gòu)。使用引入(Introduction),Aspect 可以向類中添加新的方法和變量、聲明一個(gè)類實(shí)現(xiàn)一個(gè)接口或?qū)z查異常轉(zhuǎn)換為未檢查異常(unchecked exception)。

      3.2.1.2.1 向現(xiàn)有類添加變量和方法

      假設(shè)您有一個(gè)表示持久存儲(chǔ)的數(shù)據(jù)緩存的對(duì)象。為了測(cè)量數(shù)據(jù)的“更新程度”,您可能決定向該對(duì)象添加時(shí)間戳記字段,以便容易地檢測(cè)對(duì)象是否與后備存儲(chǔ)器同步。由于對(duì)象表示業(yè)務(wù)數(shù)據(jù),根據(jù)AOP的知識(shí),我們應(yīng)該將這種機(jī)制性細(xì)節(jié)從對(duì)象中隔離。使用 AspectJ,可以用如下代碼中所顯示的語(yǔ)法來(lái)向現(xiàn)有的類添加時(shí)間戳記:

      public aspect Timestamp
      {
          private long ValueObject.timestamp;
          public long ValueObject.getTimestamp()
          {
             return timestamp;
          }
          public void ValueObject.timestamp()
          {     
             this.timestamp = System.currentTimeMillis();
          }
      }

      通過(guò)introduction,我們就非常方便的為ValueObject類型添加了timestamp的變量和相關(guān)方法。除了必須限定在哪個(gè)類上聲明引入的方法和成員變量以外,聲明引入的方法和成員變量幾乎與聲明常規(guī)類成員相同。

      3.2.1.2.2實(shí)現(xiàn)多繼承功能

      利用introduction,AspectJ允許向接口和類添加成員,也突破了Java語(yǔ)言只能單繼承的限制,允許程序按C++方式那樣實(shí)現(xiàn)多繼承。如果您希望上述的aspect Timestamp能夠泛化 (generalize),以便能夠?qū)Ω鞣N對(duì)象重用時(shí)間戳記代碼,可以定義一個(gè)稱為 TimestampedObject 的接口,并使用引入(Introduction)來(lái)將相同成員和變量添加到接口而不是添加到具體類中,如下所示:
      public interface TimestampedObject
      {
          long getTimestamp();
          void timestamp();
      }
      public aspect Timestamp
      {
          private long TimestampedObject.timestamp;
          public long TimestampedObject.getTimestamp()
          {
              return timestamp;
          }
          public void TimestampedObject.timestamp()
          {
              this.timestamp = System.currentTimeMillis();
          }
      }

      Timestamp方面由于在TimestampedObject接口中引入(introduction)了方法的實(shí)現(xiàn),使得TimestampedObject接口改變其本質(zhì),成為了一個(gè)特殊的類類型。特殊之處就在于一個(gè)已經(jīng)繼承了一個(gè)類的類類型,通過(guò)AspectJ的語(yǔ)法,仍然可以再次繼承TimestampedObject,這就間接地實(shí)現(xiàn)了類的多繼承。而這個(gè)特殊的AspectJ語(yǔ)法就是declare parents語(yǔ)法。declare parents和其它AspectJ 類型表達(dá)一樣,可以同時(shí)應(yīng)用于多個(gè)類型:
      declare parents: ValueObject || BigValueObject implements TimestampedObject;

      3.2.1.3 編譯器及工具支持

          要讓aspect能夠正常工作,必須將aspect加入到它們要修改的代碼中去。這項(xiàng)工作由AspectJ提供的ajc編譯器完成。ajc 編譯器用來(lái)編譯類和 Aspect 代碼。ajc 既可以作為編譯器也可以作為預(yù)編譯器操作,生成有效的 .class 或 .java 文件,可以在任何標(biāo)準(zhǔn) Java 環(huán)境(添加一個(gè)小的運(yùn)行時(shí) JAR)中編譯和運(yùn)行這些文件。

      要使用 AspectJ 進(jìn)行編譯,將需要顯式地指定希望在給定編譯中包含的源文件(Aspect 和類),ajc不象javac那樣簡(jiǎn)單地為相關(guān)導(dǎo)入模塊搜索類路徑。之所以這樣做,是因?yàn)闃?biāo)準(zhǔn) Java 應(yīng)用程序中的每個(gè)類都是相對(duì)分離的組件。為了正確操作,一個(gè)類只要求其直接引用的類的存在。Aspect 表示跨越多個(gè)類的行為的聚集。因此,需要將 AOP 程序作為一個(gè)單元來(lái)編譯,而不能每次編譯一個(gè)類。

      AspectJ 當(dāng)前版本的一個(gè)重要限制是其編譯器只能將aspect加入到它擁有源代碼的代碼中。也就是說(shuō),不能使用ajc將Advice添加到預(yù)編譯類中。AspectJ 團(tuán)隊(duì)認(rèn)為這個(gè)限制只是暫時(shí)的,AspectJ 網(wǎng)站承諾未來(lái)的版本(正式版 2.0)將允許字節(jié)碼的修改。

      AspectJ發(fā)行版包含了幾種開發(fā)工具。這預(yù)示著 AspectJ 將有美好的前景,因?yàn)樗砻髁俗髡邔?duì)這一部分的一個(gè)重要承諾,使 AspectJ 對(duì)于開發(fā)人員將是友好的。對(duì)于面向 Aspect 的系統(tǒng)工具支持尤其重要,因?yàn)槌绦蚰K可能受到它們所未知的模塊所影響。

      隨 AspectJ 一起發(fā)布的一個(gè)最重要的工具是圖形結(jié)構(gòu)瀏覽器,它展示了 Aspect 如何與其它系統(tǒng)組件交互。這個(gè)結(jié)構(gòu)瀏覽器既可以作為流行的 IDE 的插件,也可以作為獨(dú)立的工具。圖3.4顯示了先前討論的日志記錄示例的視圖。

      aop3.4.jpg
      圖3.4 AspectJ提供的“結(jié)構(gòu)瀏覽器”工具

      除了結(jié)構(gòu)瀏覽器和核心編譯器之外,您還可以從 AspectJ 網(wǎng)站下載一個(gè) Aspect 支持的調(diào)試器、一個(gè)javadoc工具、一個(gè)Ant任務(wù)以及一個(gè)Emacs 插件。

      3.2.2 JBoss AOP研究

      JBoss AOP關(guān)于AOP的實(shí)現(xiàn)與AspectJ是兩種完全不同的風(fēng)格。由于Java利用元數(shù)據(jù)來(lái)存儲(chǔ)有關(guān)類型、方法、字段的相關(guān)信息,因此,可以通過(guò)Java提供的反射功能獲得模塊相關(guān)的元數(shù)據(jù),對(duì)方法進(jìn)行攔截,并將被攔截的方法與aspect邏輯進(jìn)行關(guān)聯(lián)。

      3.2.2.1 攔截器(Interceptor)

      在JBoss AOP中,是用攔截器來(lái)實(shí)現(xiàn)advice的??梢宰远x攔截器,攔截方法調(diào)用、構(gòu)造函數(shù)調(diào)用以及對(duì)字段的訪問(wèn),但JBoss要求這些自定義的攔截器,必須實(shí)現(xiàn)org.jboss.aop.Interceptor接口:

      public interface Interceptor
      {
          public String getName();
          public InvocationResponse invoke(Invocation invocation) throws Throwable;
      }

      在JBoss AOP中,被攔截的字段、構(gòu)造器和方法均被轉(zhuǎn)化為通用的invoke方法調(diào)用。方法的參數(shù)接收一個(gè)Invocation對(duì)象,而方法的返回值、字段的存取以及構(gòu)造函數(shù)則被填入一個(gè)InvocationResponse對(duì)象。Invocation對(duì)象同時(shí)還驅(qū)動(dòng)攔截鏈。下面我們自定義一個(gè)攔截器,它能夠攔截構(gòu)造函數(shù)和方法的調(diào)用,并將跟蹤信息打印到控制臺(tái)上:
      import org.jboss.aop.*;
      import java.lang.reflect.*;

      public class TracingInterceptor implements Interceptor
      {
          public String getName()
          {
              return TracingInterceptor;
          }
          public InvocationResponse invoke(Invocation invocation) throws Throwable
          {
              String message = null;
              if (invocation.getType() == InvocationType.METHOD)
              {
                  Method method = MethodInvocation.getMethod(invocation);
                  message = method: + method.getName();
              }
              else
              {
                  if (invocation.getType() == InvocationType.CONSTRUCTOR)
                  {
                      Constructor c = ConstructorInvocation.getConstructor(invocation);
                      message = constructor: + c.toString();
                  }
                  else
                  {
                      // 不對(duì)字段作處理,太繁瑣;
                      return invocation.invokeNext();
                  }
                  System.out.println(Entering + message);
              }
              // 繼續(xù)。調(diào)用真正的方法或者構(gòu)造函數(shù)
              InvocationResponse rsp = invocation.invokeNext();
              System.out.println(Leaving + message);
              return rsp;
          }
      }

      在自定義的TracingInterceptor類中,invoke()方法對(duì)invocation的類型作判斷,以根據(jù)方法、構(gòu)造函數(shù)和字段類型,分別作出不同的操作。而其中,invocation.invokeNext()則表示通過(guò)一個(gè)攔截鏈獲得下一個(gè)invocation。

      定義的攔截必須在xml文件配置,使其綁定到具體的類。這個(gè)定義即為AOP中的切入點(diǎn)pointcut。例如具體的類為BusinessObject,則該pointcut在xml中的定義如下:
      <?xml version="1.0" encoding="UTF-8">
      <aop>
          <interceptor-pointcut class="BusinessObject">
              <interceptors>
                  <interceptor class="TracingInterceptor" />
              </interceptors>
          </interceptor-pointcut>
      </aop>

      上面的pointcut綁定TracingInterceptor到一個(gè)叫做BusinessObject的類。如果要將該Interceptor綁定到多個(gè)類,還可以利用正則表達(dá)式。例如,如果你想綁定由JVM載入的類,類表達(dá)式將變?yōu)?.*。如果你僅僅想跟蹤一個(gè)特定的包,那么表達(dá)式將是bruce.zhang.mypackge.*。

      當(dāng)JBoss AOP獨(dú)立運(yùn)行時(shí),任何符合 META-INF/jboss-aop.xml模式的XML文件將被JBoss AOP 運(yùn)行期程序載入。如果相關(guān)的路徑被包含在任何JAR或你的CLASSPATH目錄中,該XML文件將在啟動(dòng)時(shí),由JBoss AOP 運(yùn)行期程序載入。

      JBoss AOP還提供了過(guò)濾功能,可以通過(guò)在xml文件中配置過(guò)濾的標(biāo)志,使一些特定的方法(包括字段的訪問(wèn))被過(guò)濾,從而不再執(zhí)行Interceptor的相關(guān)邏輯。例如,我們要過(guò)濾BusinessObject類的所有g(shù)et()和set()方法,以及main()方法,則可以修改上述的xml文件:
      <?xml version="1.0" encoding="UTF-8">
      <aop>
          <class-metadata group="tracing" class=" BusinessObject ">
              <method name="(get.*)|(set.*)">
                  <filter>true</filter>
              </method>
              <method name="main">
                  <filter>true</filter>
              </method>
          </class-metadata>
      </aop>

      相應(yīng)的,Interceptor代碼也應(yīng)作相關(guān)的修改,使其能夠識(shí)別配置文件中的filter屬性:
      public class TracingInterceptor implements Interceptor
      {
          ……//getName()方法略;
          public InvocationResponse invoke(Invocation invocation) throws Throwable
          {
              String filter=(String)invocation.getMetaData(tracing, filter);
              if (filter != null && filter.equals(true))
                  return invocation.invokeNext();
              ……//后面的代碼略;
          }
      }

      3.2.2.2 引入(Introduction)

      JBoss AOP同樣提供introduction功能,通過(guò)它,就可以為現(xiàn)有的類引入第三方接口或類的API了。例如,我們可以為具體的類如BusinessObject提供Tracing的開關(guān),使得BusinessObject對(duì)象能夠根據(jù)具體的情況打開或關(guān)閉aspect的Tracing功能。為實(shí)現(xiàn)該功能,可以定義一個(gè)Tracing接口:
      public interface Tracing
      {
          void enableTracing();
          void disableTracing();
      }

      接下來(lái)需要定義一個(gè)混合類,它實(shí)現(xiàn)了接口Tracing。當(dāng)BusinessObject類被實(shí)例化時(shí),該混合類的實(shí)例就會(huì)被綁定到BusinessObject上。實(shí)現(xiàn)方法如下:
      import org.jboss.aop.Advised;

      public class TracingMixin implements Tracing
      {
          Advised advised;

          Public TracingMixin(Object obj)
          {
              this.advised = (Advised)obj;
          }
          public void enableTracing()
          {
              advised._getInstanceAdvisor().getMetaData().addMetaData("tracing", "filter", true);
          }
          public void disableTracing()
          {
              advised._getInstanceAdvisor().getMetaData().addMetaData("tracing", "filter", false);
          }
      }

      enableTracing()方法將filter屬性綁定到對(duì)象實(shí)例。disableTracing()方法作同樣的事,但是將filter屬性設(shè)置為false。

      定義了Tracing接口和實(shí)現(xiàn)了該接口的混合類后,就可以在xml文件中定義一個(gè)pointcut,強(qiáng)制BusinessObject類實(shí)現(xiàn)Tracing接口:
      <?xml version="1.0" encoding="UTF-8">
      <aop>
          <introduction-pointcut class="BusinessObject">
              <mixin>
                  <interfaces>Tracing</interfaces>
                  <class>TracingMixin</class>
                  <construction>new TracingMixin(this)</construction>
              </mixin>
          </introduction-pointcut>
      </aop>

      注意xml文件中的標(biāo)簽,它代表的含義是當(dāng)BusinessObject對(duì)象被實(shí)例化時(shí),將執(zhí)行該標(biāo)簽內(nèi)的代碼。以本例而言,當(dāng)創(chuàng)建BusinessObject對(duì)象時(shí),一個(gè)TracingMixin類的實(shí)例將被創(chuàng)建。任何單行的Java代碼都可以放到標(biāo)簽中。

      通過(guò)“引入(introduction)”功能,在處理BusinessObject對(duì)象時(shí),就可以視其為Tracing接口類型而進(jìn)行操作了,如下的示例:

      public class BusinessObject
      {
          public BusinessObject () {}
          public void helloWorld() { System.out.println(Hello World!); }

          public static void main(String[] args)
          {
              BusinessObject bo = new BusinessObject ();
              Tracing trace = (Tracing)this;
              bo.helloWorld();
             
              System.out.println("Turn off tracing.");
              trace.disableTracing();
              bo.helloWorld();
             
              System.out.println("Turn on tracing.");
              trace.enableTracing();
              bo.helloWorld();
          }
      }

      注意如下代碼:
      Tracing trace = (Tracing)this;

      此時(shí)this代表的即為BusinessObject,從Java代碼的角度來(lái)看,由于BusinessObject并沒有實(shí)現(xiàn)Tracing接口,因此這行代碼所示的顯式轉(zhuǎn)換為Tracing類型是不成功的。但通過(guò)“引入”功能,使得BusinessObject通過(guò)混合類,實(shí)現(xiàn)了Tracing接口,從而使得如上的代碼能夠順利執(zhí)行。隱含的意義就是,我們沒有修改BusinessObject的定義,而是通過(guò)AOP技術(shù),為BusinessObject擴(kuò)展實(shí)現(xiàn)了第三方提供的接口Tracing。

      3.2.3 Spring AOP研究

      Spring AOP使用純Java實(shí)現(xiàn),不需要特別的編譯過(guò)程,也不需要控制類裝載層次。與JBoss AOP相同,它仍然利用了攔截器完成對(duì)方法的攔截。然而,Spring AOP實(shí)現(xiàn)AOP的主要技術(shù)卻主要來(lái)自于AOP聯(lián)盟,如攔截器應(yīng)實(shí)現(xiàn)org.aopalliance.intercept.MethodInterceptor 接口,而所有advice必須實(shí)現(xiàn)org.aopalliance.aop.Advice標(biāo)簽接口。此外,Spring實(shí)現(xiàn)AOP的目標(biāo)也不同于其他大部分AOP框架,它的目標(biāo)不是提供及其完善的AOP實(shí)現(xiàn),而是提供一個(gè)和Spring IoC緊密整合的AOP實(shí)現(xiàn),幫助解決企業(yè)應(yīng)用 中的常見問(wèn)題。因此,Spring AOP的功能通常是和Spring IoC容器聯(lián)合使用的。AOP Advice是用普通的bean定義語(yǔ)法來(lái)定義的,Advice和pointcut本身由Spring IoC 管理。這是一個(gè)重要的其他AOP實(shí)現(xiàn)的區(qū)別。

      3.2.3.1 切入點(diǎn)(pointcut)

      Spring的切入點(diǎn)模型能夠使pointcut獨(dú)立于advice類型被重用。同樣的pointcut有可能接受不同的advice。將Pointcut接口分成兩個(gè)部分有利于重用類和方法的匹配部分,并且組合細(xì)粒度的操作(如和另一個(gè)方法匹配器執(zhí)行一個(gè)“并”的操作)。

      在Spring的切入點(diǎn)中,org.springframework.aop.Pointcut接口是重要的接口,它用來(lái)指定通知到特定的類和方法目標(biāo)。完整的接口定義如下:
      public interface Pointcut
      {
          ClassFilter getClassFilter();
          MethodMatcher getMethodMatcher();
      }

      ClassFilte類型也是一個(gè)接口,該接口被用來(lái)將切入點(diǎn)限制到一個(gè)給定的目標(biāo)類的集合。 如果matches()永遠(yuǎn)返回true,所有的目標(biāo)類都將被匹配。
      public interface ClassFilter
      {
          boolean matches(Class clazz);
      }

      MethodMatcher接口通常更加重要。完整的接口定義如下:
      public interface MethodMatcher
      {
          boolean matches(Method m, Class targetClass);
          boolean matches(Method m, Class targetClass, Object[] args);
          boolean isRuntime();
      }

      matches(Method, Class) 方法被用來(lái)測(cè)試這個(gè)切入點(diǎn)是否匹配目標(biāo)類的給定方法。這個(gè)測(cè)試可以在AOP代理創(chuàng)建的時(shí)候執(zhí)行,避免在所有方法調(diào)用時(shí)都需要進(jìn)行 測(cè)試。如果2個(gè)參數(shù)的matches()方法對(duì)某個(gè)方法返回true,并且MethodMatcher的isRuntime()也返回true,那么3個(gè)參數(shù)的matches()方法將在每次方法調(diào)用的時(shí)候被調(diào)用。這使切入點(diǎn)能夠在目標(biāo)advice被執(zhí)行之前立即查看傳遞給方法調(diào)用的參數(shù)。由于大部分MethodMatcher都是靜態(tài)的,意味著isRuntime()方法會(huì)返回false。此種情況下,3個(gè)參數(shù)的matches()方法永遠(yuǎn)不會(huì)被調(diào)用。

      Spring AOP提供了幾個(gè)實(shí)用的切入點(diǎn)實(shí)現(xiàn),其中較為常用的是正則表達(dá)式切入點(diǎn):org.springframework.aop.support.RegexpMethodPointcut,它使用Perl 5的正則表達(dá)式的語(yǔ)法。使用這個(gè)類你可以定義一個(gè)模式的列表。如果任何一個(gè)匹配,那個(gè)切入點(diǎn)將被計(jì)算成 true。用法如下:
      <bean id="settersAndAbsquatulatePointcut"
          class="org.springframework.aop.support.RegexpMethodPointcut">
          <property name="patterns">
              <list>
                  <value>.*get.*</value>
                  <value>.*absquatulate</value>
              </list>
          </property>
      </bean>

      不過(guò),更多情況下是直接使用RegexpMethodPointcut一個(gè)實(shí)用子類: RegexpMethodPointcutAdvisor。它允許我們同時(shí)引用一個(gè)advice(在Spring AOP中,advice可以是攔截器,也可以是before advice,throws advice等)。這就簡(jiǎn)化了bean的裝配,因?yàn)橐粋€(gè)bean可以同時(shí)當(dāng)作pointcut和advice,如下所示:
      <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
          <property name="advice">
              <ref local="MyInterceptor" />
          </property>
          <property name="patterns">
              <list>
                  <value>.*save.*</value>
                  <value>.*do.*</value>
              </list>
          </property>
      </bean>

      注意配置文件中的myPointcutAdvisor,在Spring AOP中,一個(gè)advisor就是一個(gè)aspect完整的模塊化表示。通過(guò)advisor,可以將pointcut和advice(在此處即為MyInterceptor)綁定起來(lái)。

      3.2.3.2 通知(advice)

      Spring AOP的advice可以跨越多個(gè)被advice對(duì)象共享,或者每個(gè)被advice對(duì)象有自己的advice。要實(shí)現(xiàn)advice,最簡(jiǎn)單的做法就是定義一個(gè)攔截器(Interceptor)。它采用了AOP聯(lián)盟(AOP Alliance)的通用AOP接口(接口定義為aopalliance.jar)。要實(shí)現(xiàn)advice,需要實(shí)現(xiàn)aopalliance.jar中定義的MethodInterceptor接口。

      例如,我們定義了一個(gè)業(yè)務(wù)對(duì)象接口BusinessObject及其實(shí)現(xiàn)類BusinessObjectImpl,該業(yè)務(wù)對(duì)象能夠存儲(chǔ)數(shù)據(jù),其定義如下:
      public interface BusinessObject
      {
          public void save();
      }
      public class BusinessObjectImpl implements BusinessObject
      {
          public void save()
          {
               System.out.println("saving domain object......");
          }
      }

      現(xiàn)在需要為業(yè)務(wù)對(duì)象BusinessObject的Save()方法,提供Lock機(jī)制。根據(jù)Spring AOP的實(shí)現(xiàn)方式,我們可以定義一個(gè)LockInterceptor來(lái)實(shí)現(xiàn)MethodInterceptor接口:
      import org.aopalliance.intercept.MethodInterceptor;
      import org.aopalliance.intercept.MethodInvocation;

      public class LockInterceptor implements MethodInterceptor
      {
          public Object invoke(MethodInvocation invocation) throws Throwable
          {
              // TODO Auto-generated method stub
              lock();
              Object ret= invocation.proceed();
              unlock();
              return ret;
          }
          private void lock()
          {
              System.out.println("lock domain object...");
          }
          private void unlock()
          {
              System.out.println("unlock domain object...");
          }
      }

      為將interceptor與具體的advice綁定起來(lái),需要在配置文件中配置bean:
      <bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>

      3.2.3.3 AOP代理與IoC容器

      由于Spring中提供了IoC容器(例如BeanFactory),因此我們可以通過(guò)Ioc機(jī)制,利用ProxyFactoryBean來(lái)創(chuàng)建AOP代理。ProxyFactoryBean和其他Spring的 FactoryBean實(shí)現(xiàn)一樣,引入一個(gè)間接的層次。如果你定義一個(gè)名字為foo的ProxyFactoryBean,引用foo的對(duì)象所看到的不是ProxyFactoryBean實(shí)例本身,而是由實(shí)現(xiàn)ProxyFactoryBean的類的 getObject()方法所創(chuàng)建的對(duì)象。這個(gè)方法將創(chuàng)建一個(gè)包裝了目標(biāo)對(duì)象 的AOP代理。

      AOP代理利用的是Java的動(dòng)態(tài)代理技術(shù),通過(guò)它就可以加載并執(zhí)行AOP組件。同時(shí),還需要通過(guò)IoC的方式將advice注入到接口以及其實(shí)現(xiàn)類。以前面的業(yè)務(wù)對(duì)象BusinessObject為例,在xml配置文件中的配置如下:
      <bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
          <property name="proxyInterfaces">
             <value>test.aop.spring.BusinessObject</value>
          </property>
          <property name="target">
             <ref local="impl" />
          </property>
          <property name="interceptorNames">
             <value>myPointcutAdvisor</value>
          </property>
      </bean>
      <bean id="impl" class="test.aop.spring.BusinessObjectImpl"/>

      通過(guò)上述對(duì)pointcut、advice、advisor和AOP代理的配置,我們就可以輕易地在Spring中實(shí)現(xiàn)AOP,例如:
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.FileSystemXmlApplicationContext;

      public class App
      {
          private BusinessObject bo = null;
          public static void main(String[] args)
          {
              ApplicationContext ctx=new FileSystemXmlApplicationContext("Bean.xml");
              bo= (BusinessObject) ctx.getBean("myAOPProxy");
              bo.save();
          }
      }

      首先,通過(guò)AOP代理獲得BusinessObject對(duì)象。當(dāng)調(diào)用BusinessObject對(duì)象的save()方法時(shí),攔截器LockInterceptor根據(jù)RegexpMethodPointcutAdvisor配置的pointcut和advice之間的關(guān)系,判定該方法的調(diào)用為join point,從而攔截該方法調(diào)用,并注入advice的執(zhí)行邏輯,即lock()和unlock(),最終實(shí)現(xiàn)了AOP。

      3.2.3.4 引入(introduction)

      在Spring AOP中,將introduction當(dāng)作advice來(lái)處理。與一般的advice一樣,introduction advice相當(dāng)于一種特殊類型的攔截通知,需要實(shí)現(xiàn)IntroductionAdvisor和IntroductionInterceptor接口,而IntroductionInterceptor接口繼承自MethodInterceptor:
      public interface IntroductionInterceptor extends MethodInterceptor
      {
          boolean implementsInterface(Class intf);
      }

      Introduction通知不能被用于任何pointcut,因?yàn)樗荒茏饔糜陬悓哟紊希皇欠椒?。我們可以只用InterceptionIntroductionAdvisor來(lái)實(shí)現(xiàn)導(dǎo)入通知,它有下面的方法:
      public interface InterceptionIntroductionAdvisor extends InterceptionAdvisor
      {
          ClassFilter getClassFilter();
          IntroductionInterceptor getIntroductionInterceptor();
          Class[] getInterfaces();
      }

      接下來(lái),我以JBoss AOP一節(jié)中的例子來(lái)說(shuō)明introduction在Spring AOP中的應(yīng)用。我們的目標(biāo)仍然是為一個(gè)已有的業(yè)務(wù)對(duì)象引入第三方接口Tracing:
      public interface Tracing
      {
          void enableTracing();
          void disableTracing();
          boolean enabled();
      }

      首先,我們需要一個(gè)做大量轉(zhuǎn)化的IntroductionInterceptor。在這里,我們繼承 org.springframework.aop.support.DelegatingIntroductionInterceptor 實(shí)現(xiàn)類。當(dāng)然我們可以直接實(shí)現(xiàn)IntroductionInterceptor接口,但是大多數(shù)情況下 DelegatingIntroductionInterceptor是最合適的。

      DelegatingIntroductionInterceptor的設(shè)計(jì)是將introduction委托到真正實(shí)現(xiàn)introduction接口的接口,隱藏完成這些工作的攔截器。委托可以使用構(gòu)造方法參數(shù)設(shè)置到任何對(duì)象中;默認(rèn)的委托就是自己(當(dāng)無(wú)參數(shù)的構(gòu)造方法被使用時(shí))。這樣在下面的例子里,委托是DelegatingIntroductionInterceptor的子類 TracingMixin。給定一個(gè)委托(默認(rèn)是自身)的 DelegatingIntroductionInterceptor實(shí)例尋找被這個(gè)委托(而不是IntroductionInterceptor)實(shí)現(xiàn)的所有接口,并支持它們中任何一個(gè)導(dǎo)入。子類如TracingMixi也可能調(diào)用suppressInterflace(Class intf) 方法來(lái)隱藏不應(yīng)暴露的接口。然而,不管IntroductionInterceptor 準(zhǔn)備支持多少接口,IntroductionAdvisor將控制哪個(gè)接口將被實(shí)際暴露。一個(gè)導(dǎo)入的接口將隱藏目標(biāo)的同一個(gè)接口的所有實(shí)現(xiàn)。

      這樣,TracingMixin繼承DelegatingIntroductionInterceptor并自己實(shí)現(xiàn)接口Tracing。父類自動(dòng)選擇支持introduction的Tracing,所以我們不需要指定它。用這種方法我們可以導(dǎo)入任意數(shù)量的接口。
      public class TracingMixin extends DelegatingIntroductionInterceptor implements Tracing
      {
          private boolean enabled;
          public void enableTracing ()
          {
              this.enabled = true;
          }

          public void disableTracing ()
          {
              this. enabled = false;
          }

          public boolean enabled()
          {
              return this.enabled;
          }
          public Object invoke(MethodInvocation invocation) throws Throwable
          {      
              return super.invoke(invocation);
          }
      }

      通常不要需要改寫invoke()方法:實(shí)現(xiàn)DelegatingIntroductionInterceptor就足夠了,如果是引入的方法,DelegatingIntroductionInterceptor實(shí)現(xiàn)會(huì)調(diào)用委托方法, 否則繼續(xù)沿著連接點(diǎn)處理。

      所需的introduction advisor是很簡(jiǎn)單的。只需保存一個(gè)獨(dú)立的TracingMixin實(shí)例,并指定導(dǎo)入的接口,在這里就是Tracing。此時(shí),TracingMixin沒有相關(guān)配置,所以我們簡(jiǎn)單地使用new來(lái)創(chuàng)建它。

      public class TracingMixinAdvisor extends DefaultIntroductionAdvisor
      {
          public TracingMixinAdvisor() {
              super(new TracingMixin(),Tracing.class);
          }
      }

      我們可以非常簡(jiǎn)單地使用這個(gè)advisor。它不需要任何配置。(但是,有一點(diǎn)是必要的:就是不可能在沒有IntroductionAdvisor 的情況下使用IntroductionInterceptor。) 和引入一樣,通常 advisor必須是針對(duì)每個(gè)實(shí)例的,并且是有狀態(tài)的。我們會(huì)有不同的TracingMixinAdvisor。每個(gè)被通知對(duì)象,會(huì)有不同的TracingMixin。advisor組成了被通知對(duì)象的狀態(tài)的一部分。

      在Spring中,Spring AOP的核心API已經(jīng)基本穩(wěn)定了。和Spring的其它部分一樣, AOP框架是模塊化的,在保留基礎(chǔ)設(shè)計(jì)的同時(shí)提供擴(kuò)展。在Spring 1.1到1.2階段有很多地方可能會(huì)有所提高,但是這些地方也保留了向后兼容性。它們是:

      (一)性能的提高:AOP代理的創(chuàng)建由工廠通過(guò)策略接口處理。因此能夠支持額外的AOP 代理類型而不影響用戶代碼或核心實(shí)現(xiàn)。
      (二)更具表達(dá)力的pointcut:Spring目前提供了一個(gè)具有表達(dá)力的切入點(diǎn)接口,同時(shí)添加了更多的切入點(diǎn)實(shí)現(xiàn)。Spring正在考慮提供一個(gè)簡(jiǎn)單但具有強(qiáng)大表達(dá)式語(yǔ)言的實(shí)現(xiàn)。

      posted on 2005-09-21 11:25 Bruce Zhang 閱讀(3051) 評(píng)論(2)  編輯  收藏 所屬分類: AOP

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多