<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    捕風(fēng)之巢

    統(tǒng)計(jì)

    留言簿(3)

    java友情鏈接

    閱讀排行榜

    評(píng)論排行榜

    了解AOP(一)

    原文:http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html

    了解AOP(第一部分)--用面向方面的編程方式分離軟件關(guān)注點(diǎn)

    摘要

    多數(shù)軟件系統(tǒng)都包含幾個(gè)跨越多個(gè)模塊的關(guān)注點(diǎn)。用面向?qū)ο蠹夹g(shù)實(shí)現(xiàn)這些關(guān)注點(diǎn)會(huì)使系統(tǒng)難以實(shí)現(xiàn),難以理解,并且不利于軟件的演進(jìn)。新的AOP(面向角度的編程方法)利用模塊化來分離軟件中橫切多模塊的關(guān)注點(diǎn)。使用AOP,你可以建立容易設(shè)計(jì),易于理解和維護(hù)的系統(tǒng)。此外,AOP可以帶來更高的產(chǎn)出,更好的質(zhì)量,更好的擴(kuò)展性,這篇文章是這個(gè)系列里三篇文章中的第一章,介紹AOP的概念和它所解決的問題。

    作者:Ramnivas Laddad

    一個(gè)關(guān)注點(diǎn)就是一個(gè)特定的目的、一塊我們感興趣的的區(qū)域。從技術(shù)的角度來說,一個(gè)典型的軟件系統(tǒng)包含一些核心的關(guān)注點(diǎn)和系統(tǒng)級(jí)的關(guān)注點(diǎn)。舉個(gè)例子來說,一個(gè)信用卡處理系統(tǒng)的核心關(guān)注點(diǎn)是借貸/存入處理,而系統(tǒng)級(jí)的關(guān)注點(diǎn)則是日志,事務(wù)完整性,授權(quán),安全性及性能問題等,許多關(guān)注點(diǎn)——我們叫它橫切關(guān)注點(diǎn)——會(huì)在多個(gè)模塊中出現(xiàn),使用現(xiàn)有的編程方法,橫切關(guān)注點(diǎn)會(huì)橫越多個(gè)模塊,結(jié)果是使系統(tǒng)難以設(shè)計(jì)、理解、實(shí)現(xiàn)和演進(jìn)。

    AOP(面向角度的編程方式)能夠比上述方法更好的分離系統(tǒng)關(guān)注點(diǎn),從而提供模塊化的橫切關(guān)注點(diǎn)。

    在這篇文章里——關(guān)于AOP的三篇文章的第一章,我首先會(huì) 解釋橫切關(guān)注點(diǎn)在一些即使是中等復(fù)雜度的軟件系統(tǒng)中也會(huì)引起的問題,接著我會(huì)介紹AOP的核心概念并演示AOP是怎樣解決橫切關(guān)注點(diǎn)問題的。

    軟件編程方法的演進(jìn)

    在計(jì)算機(jī)科學(xué)的早期階段,開發(fā)人員使用直接的機(jī)器級(jí)代碼來編程,不幸的是,程序員得花費(fèi)更多時(shí)間來考慮一種特定機(jī)器的指令集而不是手中需要解決的問題本身。慢慢的我們轉(zhuǎn)而使用允許對(duì)底層機(jī)器做某種抽象的高級(jí)語言。然后是結(jié)構(gòu)化語言,我們可以把問題分解成一些必要的過程來完成任務(wù)。但是,隨著復(fù)雜程度的增加,我們又需要更適合的技術(shù)。面向?qū)ο蟮木幊谭绞剑∣OP)使我們可以把系統(tǒng)看作是一批相互合作的對(duì)象。類允許我們把實(shí)現(xiàn)細(xì)節(jié)隱藏在接口下。多態(tài)性為相關(guān)概念提供公共的行為和接口,并允許特定的組件在無需訪問基礎(chǔ)實(shí)現(xiàn)的前提下改變特定行為。

    編程方法和語言決定了我們和計(jì)算機(jī)交流的方式。每一種新的方法學(xué)都提出一種新的分解問題的方法:機(jī)器碼、偽代碼、過程和類等。每種新的方法學(xué)都使得從系統(tǒng)需求到編程概念的映射更加自然。編程方法學(xué)的發(fā)展讓我們可以建立更加復(fù)雜的系統(tǒng),這句話反過來說也對(duì),我們能夠建立更加復(fù)雜的系統(tǒng)是因?yàn)檫@些技術(shù)允許我們處理這種復(fù)雜度。

    現(xiàn)在,大多數(shù)軟件項(xiàng)目都選擇OOP的編程方式。確實(shí),OOP已經(jīng)表明了它處理一般行為的能力,但是,我們一會(huì)兒會(huì)看到(或許你已經(jīng)感覺到了), OOP不能很好的處理橫越多個(gè)——經(jīng)常是不相關(guān)的——模塊的行為,相比之下,AOP填補(bǔ)了這個(gè)空白,它很可能會(huì)是編程方法學(xué)發(fā)展的下一個(gè)里程碑。

    把系統(tǒng)看作一批關(guān)注點(diǎn)

    我們可以把一個(gè)復(fù)雜的系統(tǒng)看作是由多個(gè)關(guān)注點(diǎn)來組合實(shí)現(xiàn)的,一個(gè)典型的系統(tǒng)可能會(huì)包括幾個(gè)方面的關(guān)注點(diǎn),如業(yè)務(wù)邏輯,性能,數(shù)據(jù)存儲(chǔ),日志和調(diào)試信息,授權(quán),安全,線程,錯(cuò)誤檢查等,還有開發(fā)過程中的關(guān)注點(diǎn),如易懂,易維護(hù),易追查,易擴(kuò)展等,圖一演示了由不同模塊實(shí)現(xiàn)的一批關(guān)注點(diǎn)組成了一個(gè)系統(tǒng)。



    圖 1. 把模塊作為一批關(guān)注點(diǎn)來實(shí)現(xiàn)

     
    圖二把需求比作一束穿過三棱鏡的光,我們讓需求之光通過關(guān)注點(diǎn)鑒別三棱鏡,就會(huì)區(qū)別出每個(gè)關(guān)注點(diǎn),同樣的方法也適用于開發(fā)階段的關(guān)注點(diǎn)。


    圖 2. 關(guān)注點(diǎn)分解: 三棱鏡法則

    開發(fā)人員建立一個(gè)系統(tǒng)以滿足多個(gè)需求,我們可以大致的把這些需求分類為核心模塊級(jí)需求和系統(tǒng)級(jí)需求。很多系統(tǒng)級(jí)需求一般來說是相互獨(dú)立的,但它們一般都會(huì)橫切許多核心模塊。舉個(gè)例子來說,一個(gè)典型的企業(yè)應(yīng)用包含許多橫切關(guān)注點(diǎn),如驗(yàn)證,日志,資源池,系統(tǒng)管理,性能及存儲(chǔ)管理等,每一個(gè)關(guān)注點(diǎn)都牽涉到幾個(gè)子系統(tǒng),如存儲(chǔ)管理關(guān)注點(diǎn)會(huì)影響到所有的有狀態(tài)業(yè)務(wù)對(duì)象。

    讓我們來看一個(gè)簡(jiǎn)單,但是具體的例子,考慮一個(gè)封裝了業(yè)務(wù)邏輯的類的實(shí)現(xiàn)框架:

    代碼:
    public class SomeBusinessClass extends OtherBusinessClass {
    ? ? // 核心數(shù)據(jù)成員

    ? ? // 其它數(shù)據(jù)成員:日志流,保證數(shù)據(jù)完整性的標(biāo)志位等

    ? ? // 重載基類的方法

    ? ? public void performSomeOperation(OperationInformation info) {
    ? ? ? ? // 安全性驗(yàn)證

    ? ? ? ? // 檢查傳入數(shù)據(jù)是否滿足協(xié)議

    ? ? ? ? // 鎖定對(duì)象以保證當(dāng)其他線程訪問時(shí)的數(shù)據(jù)完整性

    ? ? ? ? // 檢查緩存中是否為最新信息

    ? ? ? ? // 紀(jì)錄操作開始執(zhí)行時(shí)間

    ? ? ? ? // 執(zhí)行核心操作

    ? ? ? ? // 紀(jì)錄操作完成時(shí)間

    ? ? ? ? // 給對(duì)象解鎖
    ? ? }

    ? ? // 一些類似操作

    ? ? public void save(PersitanceStorage ps) {
    ? ? }

    ? ? public void load(PersitanceStorage ps) {
    ? ? }
    }


    在上面的代碼中,我們注意到三個(gè)問題,首先,其它數(shù)據(jù)成員不是這個(gè)類的核心關(guān)注點(diǎn),第二,performSomeOperation()的實(shí)現(xiàn)做了許多核心操作之外的事,它要處理日志,驗(yàn)證,線程安全,協(xié)議驗(yàn)證和緩存管理等一些外圍操作,而且這些外圍操作同樣也會(huì)應(yīng)用于其他類,第三,save() 和load()執(zhí)行的持久化操作是否構(gòu)成這個(gè)類的核心清楚的。

    橫切關(guān)注點(diǎn)的問題

    雖然橫切關(guān)注點(diǎn)會(huì)跨越多個(gè)模塊,但當(dāng)前的技術(shù)傾向于使用一維的方法學(xué)來處理這種需求,把對(duì)應(yīng)需求的實(shí)現(xiàn)強(qiáng)行限制在一維的空間里。這個(gè)一維空間就是核心模塊級(jí)實(shí)現(xiàn),其他需求的實(shí)現(xiàn)被嵌入在這個(gè)占統(tǒng)治地位的空間,換句話說,需求空間是一個(gè)n維空間,而實(shí)現(xiàn)空間是一維空間,這種不匹配導(dǎo)致了糟糕的需求到實(shí)現(xiàn)的映射

    表現(xiàn)
    用當(dāng)前方法學(xué)實(shí)現(xiàn)橫切關(guān)注點(diǎn)是不好的,它會(huì)帶來一些問題,我們可以大致把這些問題分為兩類:

    • 代碼混亂:軟件系統(tǒng)中的模塊可能要同時(shí)兼顧幾個(gè)方面的需要。舉例來說,開發(fā)者經(jīng)常要同時(shí)考慮業(yè)務(wù)邏輯,性能,同步,日志和安全等問題,兼顧各方面的需要導(dǎo)致相應(yīng)關(guān)注點(diǎn)的實(shí)現(xiàn)元素同時(shí)出現(xiàn),引起代碼混亂。
    • 代碼分散:由于橫切關(guān)注點(diǎn),本來就涉及到多個(gè)模塊,相關(guān)實(shí)現(xiàn)也就得遍布在這些模塊里,如在一個(gè)使用了數(shù)據(jù)庫的系統(tǒng)里,性能問題就會(huì)影響所有訪問數(shù)據(jù)庫的模塊。這導(dǎo)致代碼分散在各處

    結(jié)果

    混亂和分散的代碼會(huì)在多個(gè)方面影響系統(tǒng)的設(shè)計(jì)和開發(fā):

    • 可讀性差:同時(shí)實(shí)現(xiàn)幾個(gè)關(guān)注點(diǎn)模糊了不同關(guān)注點(diǎn)的實(shí)現(xiàn),使得關(guān)注點(diǎn)與其實(shí)現(xiàn)之間的對(duì)應(yīng)關(guān)系不明顯。
    • 低產(chǎn)出:同時(shí)實(shí)現(xiàn)幾個(gè)關(guān)注點(diǎn)把開發(fā)人員的注意力從主要的轉(zhuǎn)移到外圍關(guān)注點(diǎn),導(dǎo)致產(chǎn)能降低。
    • 低代碼重用率:由于這種情況下,一個(gè)模塊實(shí)現(xiàn)多個(gè)關(guān)注點(diǎn),其他需要類似功能的系統(tǒng)不能馬上使用該模塊,進(jìn)一步降低了產(chǎn)能。
    • 代碼質(zhì)量差:混亂的代碼掩蓋了代碼中隱藏的問題。而且,由于同時(shí)要處理多個(gè)關(guān)注點(diǎn),應(yīng)該特別注意的關(guān)注點(diǎn)得不到應(yīng)有的關(guān)注
    • 難以擴(kuò)展:狹窄的視角和有限的資源總是產(chǎn)生僅注意當(dāng)前關(guān)注點(diǎn)的設(shè)計(jì)。新的需求導(dǎo)致從新實(shí)現(xiàn)。由于實(shí)現(xiàn)不是模塊化的,就是說實(shí)現(xiàn)牽涉到多個(gè)模塊,為了新需求修改子系統(tǒng)可能會(huì)帶來數(shù)據(jù)的不一致,而且還需相當(dāng)規(guī)模測(cè)試來保證這些修改不會(huì)帶來bug。

      當(dāng)前解決方法

      由于多數(shù)系統(tǒng)中都包含橫切關(guān)注點(diǎn),自然的已經(jīng)形成了一些技術(shù)來模塊化橫切關(guān)注點(diǎn)的實(shí)現(xiàn),這些技術(shù)包括:混入類,設(shè)計(jì)模式和面向特定問題域的解決方式

      使用混入類,你可以推遲關(guān)注點(diǎn)的最終實(shí)現(xiàn)。基本類包含一個(gè)混入類的實(shí)例,允許系統(tǒng)的其他部分設(shè)置這個(gè)實(shí)例,舉個(gè)例子來說,實(shí)現(xiàn)業(yè)務(wù)邏輯的類包含一個(gè)混入的logger,系統(tǒng)的其他部分可以設(shè)置這個(gè)logger已得到合適的日志類型,比如logger可能被設(shè)置為使用文件系統(tǒng)或是消息中間件.在這種方式下,雖然日志的具體實(shí)現(xiàn)被推遲啦,基本類還是得包含在所有的寫日志的點(diǎn)調(diào)用日志操作和控制日志信息的代碼。

      行為型設(shè)計(jì)模式,如Visitor和Template模式,也允許你推遲具體實(shí)現(xiàn)。但是也就像混入類一樣,操作的控制——調(diào)用visitor或template的邏輯——仍然留給了基本類

      面向特定問題域的解決方式,如框架和應(yīng)用服務(wù)器,允許開發(fā)者用更模塊化的方式處理某些橫切關(guān)注點(diǎn)。比如EJB(Enterprise JavaBean,企業(yè)級(jí)javabean)架構(gòu),可以處理安全,系統(tǒng)管理,性能和容器管理的持久化(container-managed persistence)等橫切關(guān)注點(diǎn)。Bean的開發(fā)者僅需關(guān)心業(yè)務(wù)邏輯,而部署者僅需關(guān)心部署問題,如bean與數(shù)據(jù)庫的映射。但是大多數(shù)情況下,開發(fā)者還是要了解存儲(chǔ)結(jié)構(gòu)。這種方式下,你用基于XML的映射關(guān)系描述器來實(shí)現(xiàn)于數(shù)據(jù)持久化相關(guān)的橫切關(guān)注點(diǎn)。

      面向特定問題域的解決方式提供了解決特定問題的專門機(jī)制,它的缺點(diǎn)是對(duì)于每一種這樣的解決方式開發(fā)人員都必須重新學(xué)習(xí),另外,由于這種方式是特定問題域相關(guān)的,屬于特定問題域之外的橫切關(guān)注點(diǎn)需要特殊的對(duì)待

      設(shè)計(jì)師的兩難局面

      好的系統(tǒng)設(shè)計(jì)師不僅會(huì)考慮當(dāng)前需求,還會(huì)考慮到可能會(huì)有的需求以避免到處打補(bǔ)丁。這樣就存在一個(gè)問題,預(yù)知將來是很困難的,如果你漏過了將來可能會(huì)有的橫切關(guān)注點(diǎn)的需求,你將會(huì)需要修改或甚至是重新實(shí)現(xiàn)系統(tǒng)的許多部分;從另一個(gè)角度來說,太過于關(guān)注不一定需要的需求會(huì)導(dǎo)致過分設(shè)計(jì)(overdesigned)的,難以理解的,臃腫的系統(tǒng)。所以系統(tǒng)設(shè)計(jì)師處在這么一個(gè)兩難局面中:怎么設(shè)計(jì)算是過分設(shè)計(jì)?應(yīng)該寧可設(shè)計(jì)不足還是寧可過分設(shè)計(jì)?

      舉個(gè)例子來說,設(shè)計(jì)師是否應(yīng)該在系統(tǒng)中包含現(xiàn)在并不需要的日志機(jī)制?如果是的話,哪里是應(yīng)該寫日志的點(diǎn)?日志應(yīng)該記錄那些信息?相似的例子還有關(guān)于性能的優(yōu)化問題,我們很少能預(yù)先知道瓶頸的所在。常用的方法是建立系統(tǒng),profile它,然后翻新系統(tǒng)以提高性能,這種方式可能會(huì)依照 profiling修改系統(tǒng)的很多部分,此外,隨著時(shí)間的流逝,由于使用方式的變化,可能還會(huì)產(chǎn)生新的瓶頸,類庫設(shè)計(jì)師的任務(wù)更困難,因?yàn)樗茈y設(shè)想出所有對(duì)類庫的使用方式。

      總而言之,設(shè)計(jì)師很難顧及到系統(tǒng)可能需要處理的所有關(guān)注點(diǎn)。即使是在已經(jīng)知道了需求的前提下,某些建立系統(tǒng)時(shí)需要的細(xì)節(jié)也可能不能全部得到。整體設(shè)計(jì)就面臨著設(shè)計(jì)不足/過分設(shè)計(jì)的兩難局面。

      AOP基礎(chǔ)

      到目前為止的討論說明模塊化橫切關(guān)注點(diǎn)是有好處的。研究人員已經(jīng)嘗試了多種方法來實(shí)現(xiàn)這個(gè)任務(wù),這些方法有一個(gè)共同的主題:分離關(guān)注點(diǎn)。AOP是這些方法中的一種,它的目的是清晰的分離關(guān)注點(diǎn)來解決以上提到的問題。

      AOP,從其本質(zhì)上講,使你可以用一種松散耦合的方式來實(shí)現(xiàn)獨(dú)立的關(guān)注點(diǎn),然后,組合這些實(shí)現(xiàn)來建立最終系統(tǒng)。用它所建立的系統(tǒng)是使用松散耦合的,模塊化實(shí)現(xiàn)的橫切關(guān)注點(diǎn)來搭建的。與之對(duì)照,用OOP建立的系統(tǒng)則是用松散耦合的模塊化實(shí)現(xiàn)的一般關(guān)注點(diǎn)來實(shí)現(xiàn)的。在AOP終,這些模塊化單元叫方面(aspect),而在OOP中,這些一般關(guān)注點(diǎn)的實(shí)現(xiàn)單元叫做類。

      AOP包括三個(gè)清晰的開發(fā)步驟:

      • 方面分解:分解需求提取出橫切關(guān)注點(diǎn)和一般關(guān)注點(diǎn)。在這一步里,你把核心模塊級(jí)關(guān)注點(diǎn)和系統(tǒng)級(jí)的橫切關(guān)注點(diǎn)分離開來。就前面所提到的信用卡例子來說,你可以分解出三個(gè)關(guān)注點(diǎn):核心的信用卡處理,日志和驗(yàn)證。
      • 關(guān)注點(diǎn)實(shí)現(xiàn):各自獨(dú)立的實(shí)現(xiàn)這些關(guān)注點(diǎn),還用上面信用卡的例子,你要實(shí)現(xiàn)信用卡處理單元,日志單元和驗(yàn)證單元。
      • 方面的重新組合:在這一步里,方面集成器通過創(chuàng)建一個(gè)模塊單元——方面來指定重組的規(guī)則。重組過程——也叫織入或結(jié)合——?jiǎng)t使用這些信息來構(gòu)建最終系統(tǒng),還拿信用卡的那個(gè)例子,你可以指定(用某種AOP的實(shí)現(xiàn)所提供的語言)每個(gè)操作的開始和結(jié)束需要紀(jì)錄,并且每個(gè)操作在涉及到業(yè)務(wù)邏輯之前必須通過驗(yàn)證。




      圖 3. AOP 開發(fā)的步驟

      AOP與OOP的不同關(guān)鍵在于它處理橫切關(guān)注點(diǎn)的方式,在AOP中,每個(gè)關(guān)注點(diǎn)的實(shí)現(xiàn)都不知道其它關(guān)注點(diǎn)是否會(huì)‘關(guān)注’它,如信用卡處理模塊并不知道其它的關(guān)注點(diǎn)實(shí)現(xiàn)正在為它做日志和驗(yàn)證操作。它展示了一個(gè)從OOP轉(zhuǎn)化來的強(qiáng)大的開發(fā)范型。

      注意:一個(gè)AOP實(shí)現(xiàn)可以借助其它編程范型作為它的基礎(chǔ),從而原封不動(dòng)的保留其基礎(chǔ)范型的優(yōu)點(diǎn)。例如,AOP可以選擇OOP作為它的基礎(chǔ)范型,從而把OOP善于處理一般關(guān)注點(diǎn)的好處直接帶過來。用這樣一種實(shí)現(xiàn),獨(dú)立的一般關(guān)注點(diǎn)可以使用OOP技術(shù)。這就像過程型語言是許多OOP語言的基礎(chǔ)一樣。

      織入舉例
      織入器——一個(gè)處理器——組裝一個(gè)個(gè)關(guān)注點(diǎn)(這個(gè)過程叫做織入)。就是說,它依照提供給它的規(guī)則把不同的執(zhí)行邏輯段混編起來。

      為了說明代碼織入,讓我們回到信用卡處理的例子,為了簡(jiǎn)單起見,我們只考慮兩個(gè)操作:存入和取出,并且我們假設(shè)已經(jīng)有了一個(gè)合適的logger.

      來看一下下面的信用卡模塊:
      代碼:

      public class CreditCardProcessor {
      ? ? public void debit(CreditCard card, Currency amount)
      ? ? ? ?throws InvalidCardException, NotEnoughAmountException,
      ? ? ? ? ? ? ? CardExpiredException {
      ? ? ? ? // 取出邏輯
      ? ? }
      ? ?
      ? ? public void credit(CreditCard card, Currency amount)
      ? ? ? ? throws InvalidCardException {
      ? ? ? ? // 存入邏輯

      ? ? }
      }


      下面是日志接口
      代碼:

      public interface Logger {
      ? ? public void log(String message);
      }


      所需組合需要如下織入規(guī)則,這里用自然語言來表達(dá)(本文的后面會(huì)提供這些織入規(guī)則的程序版本):
      [list=a]
    • 紀(jì)錄每個(gè)公共操作的開始
    • 紀(jì)錄每個(gè)公共操作的結(jié)束
    • 紀(jì)錄所有公共方法拋出的異常


    織入器就會(huì)使用這些織入規(guī)則和關(guān)注點(diǎn)實(shí)現(xiàn)來產(chǎn)生與如下代碼有相同效果的代碼:

    代碼:
    public class CreditCardProcessorWithLogging {
    ? ? Logger _logger;

    ? ? public void debit(CreditCard card, Money amount)
    ? ? ? ? throws InvalidCardException, NotEnoughAmountException,
    ? ? ? ? ? ? ? ?CardExpiredException {
    ? ? ? ? _logger.log("Starting CreditCardProcessor.credit(CreditCard,
    Money) "
    ? ? ? ? ? ? ? ? ? ? + "Card: " + card + " Amount: " + amount);
    ? ? ? ? // 取出邏輯
    ? ? ? ? _logger.log("Completing CreditCardProcessor.credit(CreditCard,
    Money) "
    ? ? ? ? ? ? ? ? ? ? + "Card: " + card + " Amount: " + amount);
    ? ? }
    ? ?
    ? ? public void credit(CreditCard card, Money amount)
    ? ? ? ? throws InvalidCardException {
    ? ? ? ? System.out.println("Debiting");
    ? ? ? ? _logger.log("Starting CreditCardProcessor.debit(CreditCard,
    Money) "
    ? ? ? ? ? ? ? ? ? ? + "Card: " + card + " Amount: " + amount);
    ? ? ? ? // 存入邏輯
    ? ? ? ? _logger.log("Completing CreditCardProcessor.credit(CreditCard,
    Money) "
    ? ? ? ? ? ? ? ? ? ? + "Card: " + card + " Amount: " + amount);

    ? ? }
    }


    AOP語言剖析

    就像其他編程范型的實(shí)現(xiàn)一樣,AOP的實(shí)現(xiàn)有兩部分組成:語言規(guī)范和實(shí)現(xiàn)。語言規(guī)范描述了語言的基礎(chǔ)單元和語法。語言實(shí)現(xiàn)則按照語言規(guī)范來驗(yàn)證代碼的正確性并把代碼轉(zhuǎn)成目標(biāo)機(jī)器的可執(zhí)行形式。這一節(jié),我來解釋一下AOP組成部分。

    AOP語言規(guī)范
    從抽象的角度看來,一種AOP語言要說明下面兩個(gè)方面:

    • 關(guān)注點(diǎn)的實(shí)現(xiàn):把每個(gè)需求映射為代碼,然后,編譯器把它翻譯成可執(zhí)行代碼,由于關(guān)注點(diǎn)的實(shí)現(xiàn)以指定過程的形式出現(xiàn),你可以使用傳統(tǒng)語言如C,C++,Java等。
    • 織入規(guī)則規(guī)范:怎樣把獨(dú)立實(shí)現(xiàn)的關(guān)注點(diǎn)組合起來形成最終系統(tǒng)呢?為了這個(gè)目的,需要建立一種語言來指定組合不同的實(shí)現(xiàn)單元以形成最終系統(tǒng)的規(guī)則,這種指定織入規(guī)則的語言可以是實(shí)現(xiàn)語言的擴(kuò)展,也可以是一種完全不同的語言。


    AOP語言的實(shí)現(xiàn)

    AOP的編譯器執(zhí)行兩步操作:

    1. 組裝關(guān)注點(diǎn)。
    2. 把組裝結(jié)果轉(zhuǎn)成可執(zhí)行代碼

    AOP實(shí)現(xiàn)可以用多種方式實(shí)現(xiàn)織入,包括源碼到源碼的轉(zhuǎn)換。它預(yù)處理每個(gè)方面的源碼產(chǎn)生織入過的源碼,然后把織入過的源碼交給基礎(chǔ)語言的編譯器產(chǎn)生最終可執(zhí)行代碼。比如,使用這種方式,一個(gè)基于Java的AOP實(shí)現(xiàn)可以先把不同的方面轉(zhuǎn)化成Java源代碼,然后讓Java編譯器把它轉(zhuǎn)化成字節(jié)碼。也可以直接在字節(jié)碼級(jí)別執(zhí)行織入;畢竟,字節(jié)碼本身也是一種源碼。此外,下面的執(zhí)行系統(tǒng)——Java虛擬機(jī)——也可以是方面認(rèn)知的,基于Java的AOP 實(shí)現(xiàn)如果使用這種方式的話,虛擬機(jī)可以先裝入織入規(guī)則,然后對(duì)后來裝入的類都應(yīng)用這種規(guī)則,也就是說,它可以執(zhí)行just-in-time的方面織入。

    AOP的好處

    AOP可幫助我們解決上面提到的代碼混亂和代碼分散所帶來的問題,它還有一些別的好處:

    • 塊化橫切關(guān)注點(diǎn):AOP用最小的耦合處理每個(gè)關(guān)注點(diǎn),使得即使是橫切關(guān)注點(diǎn)也是模塊化的。這樣的實(shí)現(xiàn)產(chǎn)生的系統(tǒng),其代碼的冗余小。模塊化的實(shí)現(xiàn)還使得系統(tǒng)容易理解和維護(hù)
    • 系統(tǒng)容易擴(kuò)展:由于方面模塊根本不知道橫切關(guān)注點(diǎn),所以很容易通過建立新的方面加入新的功能,另外,當(dāng)你往系統(tǒng)中加入新的模塊時(shí),已有的方面自動(dòng)的橫切進(jìn)來,使系統(tǒng)的易于擴(kuò)展
    • 設(shè)計(jì)決定的遲綁定:還記得設(shè)計(jì)師的兩難局面嗎?使用AOP,設(shè)計(jì)師可以推遲為將來的需求作決定,因?yàn)樗梢园堰@種需求作為獨(dú)立的方面很容易的實(shí)現(xiàn)。
    • 更好的代碼重用性:由于AOP把每個(gè)方面實(shí)現(xiàn)為獨(dú)立的模塊,模塊之間是松散耦合的,舉例來說,你可以用另外一個(gè)獨(dú)立的日志寫入器方面(替換當(dāng)前的)把日志寫入數(shù)據(jù)庫,以滿足不同的日志寫入要求。
      總的來說,松散耦合的實(shí)現(xiàn)意味著更好的代碼重用性, AOP在使系統(tǒng)實(shí)現(xiàn)松散耦合這一點(diǎn)上比OOP做得更好。


    AspectJ:一個(gè)Java的AOP實(shí)現(xiàn)

    AspectJ是一個(gè)可免費(fèi)獲得的由施樂公司帕洛阿爾托研究中心(Xerox PARC)開發(fā)Java的AOP實(shí)現(xiàn),它是一個(gè)多功能的面向方面的Java擴(kuò)展。它使用Java作為單個(gè)關(guān)注點(diǎn)的實(shí)現(xiàn)語言,并擴(kuò)展Java以指定織入規(guī)則。這些規(guī)則是用切入點(diǎn)(pointcuts)、聯(lián)結(jié)點(diǎn)(join points),通知(advice)和方面(aspect)來說明的。聯(lián)結(jié)點(diǎn)是定義在程序執(zhí)行過程之間的點(diǎn),切入點(diǎn)由用來指定聯(lián)結(jié)點(diǎn)的語言構(gòu)造,通知定義了要在切入點(diǎn)上執(zhí)行的代碼片,而方面則是這些基礎(chǔ)元素的組合。

    另外,AspectJ允許以多種方式用方面和類建立新的方面,你可以引入新的數(shù)據(jù)成員和方法,或是聲明一個(gè)新的類來繼承和實(shí)現(xiàn)另外的類或接口。

    AspectJ的織入器——AspectJ的編譯器——負(fù)責(zé)把不同的方面組合在一起,由于由AspectJ編譯器建立的最終系統(tǒng)是純Java字節(jié)碼,它可以運(yùn)行在任何符合Java標(biāo)準(zhǔn)的虛擬機(jī)上。而且,AspectJ還提供了一些工具如調(diào)試器和Java IDE集成等,我將會(huì)在本系列的第二、三部分詳細(xì)講解這些。

    下面是我在上面用自然語言描述的日志方面的織入規(guī)則的AspectJ實(shí)現(xiàn),由于我將會(huì)在第二部分詳細(xì)介紹AspectJ,所以如果你不能透徹的看懂它的話也不必?fù)?dān)心。關(guān)鍵是你應(yīng)該注意到信用卡處理過程本身一點(diǎn)都不知道日志的事。

    代碼:

    public aspect LogCreditCardProcessorOperations {
    ? ? Logger logger = new StdoutLogger();

    ? ? pointcut publicOperation():
    ? ? ? ? execution(public * CreditCardProcessor.*(..));

    ? ? pointcut publicOperationCardAmountArgs(CreditCard card,
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Money amount):
    ? ? ? ? publicOperation() && args(card, amount);

    ? ? before(CreditCard card, Money amount):
    ? ? ? ? publicOperationCardAmountArgs(card, amount) {
    ? ? ? ? logOperation("Starting",
    ? ? ? ? ? ? ?thisjoin point.getSignature().toString(), card, amount);
    ? ? }

    ? ? after(CreditCard card, Money amount) returning:
    ? ? ? ? publicOperationCardAmountArgs(card, amount) {
    ? ? ? ? logOperation("Completing",
    ? ? ? ? ? ? thisjoin point.getSignature().toString(), card, amount);
    ? ? }

    ? ? after (CreditCard card, Money amount) throwing (Exception e):
    ? ? ? ? publicOperationCardAmountArgs(card, amount) {
    ? ? ? ? logOperation("Exception " + e,
    ? ? ? ? ? ? thisjoin point.getSignature().toString(), card, amount);
    ? ? }

    ? ? private void logOperation(String status, String operation,
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CreditCard card, Money amount) {
    ? ? ? ? logger.log(status + " " + operation +
    ? ? ? ? ? ? ? ? ? ?" Card: " + card + " Amount: " + amount);
    ? ? }
    }




    我需要AOP嗎?

    AOP僅僅是解決設(shè)計(jì)上的缺點(diǎn)嗎?在AOP里,每個(gè)關(guān)注點(diǎn)的實(shí)現(xiàn)的并不知道是否有其它關(guān)注點(diǎn)關(guān)注它,這是AOP和OOP的主要區(qū)別,在AOP里,組合的流向是從橫切關(guān)注點(diǎn)到主關(guān)注點(diǎn),而OOP則相反,但是,OOP可以和AOP很好的共存。比如,你可以使用一個(gè)混入類來做組合,既可以用AOP實(shí)現(xiàn),也可以用OOP實(shí)現(xiàn),這取決你對(duì)AOP的接受程度。在這兩種情況下,實(shí)現(xiàn)橫切關(guān)注點(diǎn)的混入類實(shí)現(xiàn)都無需知道它自己是被用在類中還是被用在方面中。舉個(gè)例子來說,你可以把一個(gè)日志寫入器接口用作某些類的混入類或是用作一個(gè)日志方面。因而,從OOP到AOP是漸進(jìn)的。

    了解AOP

    在這篇文章里,你看到了橫切關(guān)系帶來的問題,這些問題的當(dāng)前解決方法,以及這些方法的缺點(diǎn)。你也看到了AOP是怎樣克服這些缺點(diǎn)的。AOP的編程方式試圖模塊化橫切關(guān)注點(diǎn)的實(shí)現(xiàn),提供了一個(gè)更好更快的軟件開發(fā)方式。

    如果你的系統(tǒng)中涉及到多個(gè)橫切關(guān)注點(diǎn),你可以考慮進(jìn)一步了解AOP,它的實(shí)現(xiàn),它的好處。AOP很可能會(huì)是編程方式的下一個(gè)里程碑。請(qǐng)繼續(xù)關(guān)注本系列的第二、第三部分。

    posted on 2006-10-25 10:06 捕風(fēng) 閱讀(223) 評(píng)論(0)  編輯  收藏 所屬分類: java高級(jí)

    主站蜘蛛池模板: 黄色免费网址大全| a级毛片毛片免费观看久潮| 美女视频黄a视频全免费网站色 | 巨胸喷奶水www永久免费| 国产成人免费永久播放视频平台| 久久久久亚洲AV成人无码| 水蜜桃视频在线观看免费| 精品免费国产一区二区三区| 亚洲校园春色小说| 久久九九全国免费| 亚洲国产成人久久精品影视| 99re6在线视频精品免费| 亚洲国产成人精品久久| 午夜老司机永久免费看片| 国产亚洲3p无码一区二区| 成年网站免费入口在线观看| 亚洲人成人无码网www国产| 无码亚洲成a人在线观看| 成人永久免费高清| 日本系列1页亚洲系列| 亚洲精品麻豆av| 国产精品1024永久免费视频| 中文字幕亚洲色图| 免费99精品国产自在现线| 亚洲区视频在线观看| 中文字幕无码精品亚洲资源网| 国产福利免费视频 | 亚洲第一视频在线观看免费| 国产亚洲美女精品久久| 亚洲精品无码专区2| 毛片免费vip会员在线看| 亚洲Aⅴ在线无码播放毛片一线天| 久久精品国产亚洲AV麻豆不卡| 久久久久久久99精品免费| 老司机免费午夜精品视频| 国产亚洲精品bv在线观看| 成人免费在线视频| 777成影片免费观看| 亚洲一区AV无码少妇电影| 亚洲国产成人精品久久久国产成人一区二区三区综 | 国产yw855.c免费视频|