作者:Bill Burke;yahveyeye 原文地址:http://www./pub/a/onjava/2004/08/25/aoa.html 中文地址:http://www./resource/article/44/44052_Annotation+Aop.html 關(guān)鍵詞: Annotation Aop Annotation是J2SE5.0的一項新功能,它允許您附加元數(shù)據(jù)到Java構(gòu)建中。同時,面向方面編程(AOP)是一個相當(dāng)新的技術(shù),它可以使您封裝某些行為,這些行為是在使用面向?qū)ο螅∣O)技術(shù)時會更為混亂,困難甚至是不可能完成。這兩項技術(shù)結(jié)合起來給框架開發(fā)者開發(fā)的APIs更好的表達(dá)方式。本文深入結(jié)合這些技術(shù),使用Jboss AOP框架,以不同的代碼范例向您展示如何結(jié)合兩者來實際地擴展Java 語言。 相關(guān)文章: Java Annotation入門: http://www./resource/article/44/44048_Java+Annotation.html Annotation概述 首先讓我們給出這兩項技術(shù)的一個概述。Annotation是JDK5.0的新功能,它在JSR-175規(guī)范中有詳細(xì)定義。它們允許您以安全的方法定義元數(shù)據(jù)并應(yīng)用到類,方法,構(gòu)造程序,字段或參數(shù)中。對于你們中熟悉XDoclet的人來說,Annotation將非常直觀,您可以用來聲明標(biāo)簽以產(chǎn)生代碼。兩者的主要不同是Annotation是Java語言的一部分而XDoclet標(biāo)簽可能會打錯并且難以創(chuàng)建。我喜歡用例子來說明,所以讓我們展示一個簡單的例子。 要定義一個Annotation,您所要做的就是聲明一個特殊類型的Java接口。 清單1:Orange.java package org.jboss.collors; 定義了這個接口,您就可以用來提供更多的描述給您的Java元素。 清單2:Foo.java package org.jboss.examples; 那么我們可以用Annotation來干什么呢?一些人想用Annotation來產(chǎn)生代碼并替代XDoclet,其他人,象J2EE和EJB3.0專家組,將它視為部署描述符的替代。本文談?wù)撛贏OP中如何使用Annotation AOP概述 有許多的文章和書籍解釋AOP到底是什么,例如Graham O‘Regan的ONJava文章“Introduction to Aspect-Oriented Programming."我將在本文給出一個快速的概覽,但我鼓勵您在線做更多的研究。 假設(shè)您要添加代碼到一個應(yīng)用程序去測試調(diào)用一個特定的java方法所需的總的時間。該代碼可能看起來如下: 清單3: public class BankAccount 雖然這些代碼能夠正常工作,但這個方法有一些問題: 1.它難以打開和關(guān)閉測試,您必須在try/finally塊中對每個方法或購置函數(shù)手工增加代碼以進(jìn)行基準(zhǔn)測試。 2。這一輪廓代碼并不真正屬于貫穿整個應(yīng)用的代碼。它使得您的代碼臃腫并難以理解,因為您必須將計時放在try/finally塊中。 3、如果您想擴展它的功能以包含一個方法或是失敗計數(shù),或甚至是注冊這些統(tǒng)計數(shù)據(jù)到一個更為復(fù)雜的報告機制中,您必須修改大量不同文件(又一次)。 Metrics類提供了一個什么是橫切(cross-cutting)關(guān)系的完美,簡潔的小例子。Jboss AOP以一種含蓄的方式提供了一個簡單的方法來封裝和應(yīng)用這樣的關(guān)系,這樣某些象度量操作代碼不會弄亂您的編碼。讓我們稍為深入到Jboss AOP一些來看看如何實現(xiàn)。 為了使用Jboss AOP封裝度量功能,您首先需要定義一個方面來指出該度量行為。 清單4: public class Metrics 一個方面只是一個具有定義了您想要附加到您的對象模型的行為的普通Java類。這些方法的簽名必須返回一個java.lang.Object并且必須具有一個(并且只有一個)Jboss AOP 調(diào)用對象參數(shù),它被用來封裝方法,構(gòu)造函數(shù)或字段調(diào)用。方法名可以是任何你想要的并且當(dāng)您綁定該方面到您的代碼片斷時被引用。 下面要做的事情就是實際應(yīng)用方面到您想要它勾勒一個方法的執(zhí)行的某個程序點。大多數(shù)AOP框架提供了一個指向表達(dá)式語言,在此處您可以定義您想要某個方面行為被附加到的位置。下面是在Jboss AOP中的做法。 清單5:jboss-aop.xml <aop> 采用在Metrics.java中對方面的定義和jboss-aop.xml中的指向定義,該度量代碼現(xiàn)在以含蓄而又透明地應(yīng)用到BankAccount.withdraw()方法中并能在勾勒代碼不再需要時輕易地移除。 對于Jboss AOP更多的信息,請查詢分發(fā)包中的指南。其中具有大約20個例子來帶領(lǐng)您漫游如何使用Jboss AOP框架。 噓!現(xiàn)在我們已經(jīng)進(jìn)行了一個概覽,讓我們深入到本文的中心內(nèi)容。我將再次給您提供一些例子,因為這是我所知道的講授一個新的概念的最好的方法。 正如我前面說的,Annotation加上AOP幾乎是給予您擴展Java語言的能力。Annotation提供了聲明新的,可兼容的,類型安全的語法機制。AOP提供了封裝和應(yīng)用新的行為到一個語法表達(dá)式的機制。 方法Annotation和AOP 讓我們看看如何使用方法Annotation和AOP。使用Annotation和AOP并應(yīng)用到一個方法類似于使用Java的synchronized關(guān)鍵字。當(dāng)您設(shè)定一個方法為synchronized,您在告訴JVM:您想該方法在被調(diào)用時以一種特殊的方式進(jìn)行。Annotation允許您定義一個新的關(guān)鍵字來觸發(fā)您自己的特殊的定制行為。AOP給予您封裝這一行為的能力并將其“編織”進(jìn)該方法的執(zhí)行中。再次的,這一概念的最佳描述是通過一個例子。 讓我們假設(shè)我們想要添加新的語法,使用該語法使得我們可以在方法被標(biāo)簽為@Oneway時,在后臺以另一個線程調(diào)用這個void方法??梢韵筮@樣使用新的語法: 清單6: Import org.jboss.aspects.Oneway; 當(dāng)someMethod()在main中被調(diào)用,它將異步運行,這樣main中的代碼可以并行執(zhí)行其他任務(wù)。 要實現(xiàn)這一功能,首先要在一個Annotation中為我們的@Oneway標(biāo)簽定義新的Java語法. 清單7:Oneway.java package org.jboss.aspects; 夠簡單的。@Target標(biāo)簽允許您縮小Annotation可以應(yīng)用的地方。在本例中,我們的@OnewayAnnotation只能應(yīng)用到一個方法。記住,這些都是J2SE5.0百分之百可用的純Java。 下面要做的事是定義一個封裝我們的@Oneway行為的方面類。 清單8:OnewayAspect.java package org.jboss.aspects; 這個方面夠簡單。oneway()方法拷貝invocation,創(chuàng)建一個線程,在后臺啟動整個調(diào)用并返回。我們可以想象一個更為復(fù)雜的例子:使用J2SE 5.0 java.util.concurrent包中的某些新的Executors,但這些代碼很有希望闡明了如何基于這個例子構(gòu)建更為復(fù)雜的實現(xiàn)。 最后必須要做的事情是指定當(dāng)@OnewayAnnotation在一個方法中聲明時觸發(fā)OnewayAspect應(yīng)用的指向表達(dá)式。 清單9:jboss-aop.xml <aop> 該指向表達(dá)式規(guī)定任何具有@Oneway標(biāo)簽的void方法都應(yīng)該有OnewayAspect.oneway()方法在它本身執(zhí)行前被執(zhí)行。隨著Annotation,方面和現(xiàn)在定義的指向表達(dá)式,@Oneway語法現(xiàn)在可以用于您的應(yīng)用程序中。一個簡單,清晰,易于實現(xiàn)的方法來擴展Java 語言! 字段Annotation和AOP 讓我們看看如何使用字段Annotation和AOP。使用Annotation和AOP,您可以改變一個對象的字段或是作為一個類的靜態(tài)成員的實際存儲方式。在這個例子里我們要完成的是當(dāng)您將一個字段(靜態(tài)或是成員)標(biāo)記上@ThreadBased,盡管是將它存儲在java.lang.ThreadLocal,但它的值依然正常。當(dāng)然,您可以直接使用ThreadLocal變量,但問題是ThreadLocal并非一個類型并且您必須使用“麻煩的”(好,它們并沒有那么羅嗦)get()和set()方法。那么我們現(xiàn)在做的就是創(chuàng)建一個ThreadLocal類型的字段。我們主要的將創(chuàng)建一個稱為@Thradbased變量的新的Java字段類型。 象這樣使用新的類型: 清單10: import org.jboss.aspects.Threadbased; 為了實現(xiàn)這個功能,我們必須先定義Annotation 清單11:Threadbased.java package org.jboss.aspects; 夠簡單。@Target標(biāo)簽允許您縮小Annotation可以應(yīng)用的地方。在本例中,我們的@ThreadbasedAnnotation只能應(yīng)用到字段。 下面的事情是定義封裝我們的ThreadLocal行為的方面。 清單12:ThreadbasedAspect.java package org.jboss.aspects; ThreadbasedAspect 封裝到一個Java字段的訪問。它里面具有一個專門的ThreadLocal變量跟蹤thradlocal變?yōu)橐粋€特殊的字段。它還有一個單獨的access()方法,該方法根據(jù)一個字段的get或set方法是否被調(diào)用決定它是否被調(diào)用。這些方法委托給ThreadLocal來獲得字段的當(dāng)前值。 最后,我們必須定義一個指向表達(dá)式,當(dāng)@ThreadbasedAnnotation在某個字段被指定時觸發(fā)ThreadbasedAspect的應(yīng)用。 清單13:jboss-aop.xml <aop> 只有當(dāng)我們具有多個@Threadbased變量定義在同一個類時,我們需要為每個靜態(tài)字段分配一個ThreadbasedAspect實例。對于成員變量,我們需要為每個字段,每個對象實例分配一個ThreadbasedAspect實例。為了促進(jìn)這一行為,方面定義通過設(shè)定實例為PER_JOINPOINT限制方面類的實例何時和何地被分配出去的范圍。如果我們不做限制,Jboss AOP會只分配一個ThreadbasedAspect實例并且不同的字段會共享相同的ThreadLocal接口——這不是我們所希望的。 好就這樣。一個清晰容易的擴展Java來指定一個新的特殊類型的方法。注意:該特殊的方法來自Jboss AOP束。 依賴注入 字段Annotation和AOP可以使用的一個有趣的地方是依賴注入。依賴注入是關(guān)于對象聲明它們需要什么信息,配置或服務(wù)引用以及運行時自動注入這些依賴而不是用代碼明確地在一個注冊中心查找。在J2EE領(lǐng)域,獲得javax.transaction.TransactionManager服務(wù)的訪問并未標(biāo)準(zhǔn)化并且實際上不同的廠商有不同的實現(xiàn)。許多框架開發(fā)者需要使用TransactionManager來實現(xiàn)定制事務(wù)服務(wù)。使用字段AnnotationAOP提供依賴注入并抽取出一個需要TransactionManager的組件如何引用它的細(xì)節(jié)是一個了不起的方法。讓我們定義一個方面,它將注入一個TransactionManager引用到一個字段值中。 首先,我們再次定義我們的Annotation。 清單14:Inject.java package org.jboss.aspects; 下面我們將定義方面類,它封裝了TransactionManager的解析。該方面是特定于JBoss應(yīng)用服務(wù)器,但您可以定義為每個廠商定義不同的實現(xiàn)。 清單15:InjectTMAspect.java package org.jboss.aspects; 最后,我們必須定義XML綁定來觸發(fā)當(dāng)@Inject標(biāo)簽應(yīng)用到一個字段時InjectTMAspect的應(yīng)用。指向表達(dá)式基本上說明了對任意一個標(biāo)記為@Inject的TransactionManager字段應(yīng)用InjectTMAspect。 清單16: <aop> 現(xiàn)在Annotation、方面類和XML綁定已經(jīng)定義,我們可以在我們的代碼中使用了。 清單17: import javax.transaction.TransactionManager; 更多預(yù)打包例子 Jboss AOP不僅僅是關(guān)于AOP框架。它還有一個豐富的方面庫,您可以直接在您的應(yīng)用中使用。在這個庫中是一個比我們現(xiàn)在在本文展示的例子更為復(fù)雜的Annotation方面集。這些方面包括異步調(diào)用,事務(wù)劃分,事務(wù)鎖定和基于角色的安全。讓我們簡要地瀏覽一下以提供給您一個更好的關(guān)于Annotation和AOP共同工作的考慮。 異步方面 Jboss AOP異步方面允許您定義任何方法為異步的,這樣它可以在后臺被執(zhí)行。這對于我們的@Oneway例子來說有些困難,因為它使用Oswego并行包中的執(zhí)行器工具,并為那些具有一個返回類型的方法提供了一個方法來異步地接收回響應(yīng)。要使用這個方面,您只需標(biāo)記一個方法為@Asybchronous. 清單18: public Foo { @Asynchronous標(biāo)簽的應(yīng)用做了一些事情。與在本文中的@Oneway例子一樣,它應(yīng)用一個在后臺運行該方法的方面。而且,采用@Asynchronous標(biāo)簽,您并不僅限于void方法并可于實際上返回一個值的方法進(jìn)行交互。當(dāng)@Asynchronous標(biāo)簽被應(yīng)用,它強制Foo類實現(xiàn)AsynchronousFacade接口。在AOP領(lǐng)域,這稱為接口引入(interface introduction)。AsynchronousFacade接口允許您預(yù)測一個響應(yīng)或以超時限定等待一個響應(yīng)。最好用一個例子來解釋。 清單19: Foo foo = new Foo(); 您可以啟動多個不同對象的多個不同方法的多個調(diào)用,并異步積累它們的響應(yīng)。 事務(wù)鎖定 有時在J2EE事務(wù)期間而不是一個方法執(zhí)行,構(gòu)造函數(shù)調(diào)用或同步塊執(zhí)行期間同步一個對象或類會很有用。對這類事務(wù)同步或鎖定,Jboss AOP發(fā)明了@TxSynchronized關(guān)鍵字。您可以使用@TxSynchronized在任意成員或靜態(tài)方法已經(jīng)構(gòu)造函數(shù)上。 清單20: import org.jboss.aspects.txlock.TxSynchronized; 如果一個被標(biāo)記為@TxSynchronized的構(gòu)造函數(shù)或靜態(tài)方法被調(diào)用,類的鎖監(jiān)視器會在事務(wù)執(zhí)行期間被保持著。如果一個標(biāo)記為@TxSynchronized的成員方法被調(diào)用,該對象實例的鎖監(jiān)視器將被保持直到目前的事務(wù)提交或回退??刂圃撔袨榈姆矫嬉矊⒆鏊梨i檢測并在發(fā)生死鎖時拋出RuntimeException。 J2EE 散餐(原文法文:a la carte)之:事務(wù)劃分 EJB3.0已經(jīng)定義了一些Annotation進(jìn)行事務(wù)劃分。Jboss AOP在此基礎(chǔ)上構(gòu)建。這樣您可以通過指定Annotation應(yīng)用事務(wù)劃分到任意方法(靜態(tài)或成員)以及任何Java類構(gòu)造函數(shù)。 清單21: import org.jboss.aspects.tx.*; J2EE 散餐之:基于角色的安全 EJB 3.0也定義了一些Annotation實現(xiàn)基于角色的安全。Jbos AOP是基于此構(gòu)建的,所以您可以應(yīng)用基于角色的安全到任何的字段或方法(靜態(tài)或成員)已經(jīng)構(gòu)造函數(shù)。 清單22: import org.jboss.aspects.security.*; EJB演變 隨著AOP與EJB規(guī)范一起漸漸成熟,我真正希望發(fā)生的是EJB規(guī)范定義的Annotation將能在任何上下文作為新的Java語言的形容詞被使用,而不是讓它們有限的使用在會話bean中。想象一下,一個真正的無狀態(tài)bean僅僅成為一個明文Java類的一個靜態(tài)方法集。 清單23: public MySessionBean 無論如何,這些關(guān)于AOP和EJB的討論很可能就是為了EJB4.0。 結(jié)論 并非是限制J2SE5.0Annotation用于代碼生成,Annotation和AOP可以被結(jié)合起來提供新的能力給框架開發(fā)者。這一結(jié)合允許開發(fā)者定義新的具有行為附加到其上的Java語法?;旧希园踩姆绞綌U展Java語言的能力已盡在掌握。 資源 ·Matrix-Java開發(fā)者社區(qū):http://www. ·: 關(guān)于作者 Bill Burke :JBoss 首席架構(gòu)師. |
|