相信知道Spring的朋友都知道兩個名詞:IOC和AOP,對於Spring的IOC和AOP並不是本文所討論的范圍,IOC是十分好理解的,也是相對簡單的技朮,只要不是JAVA的初學(xué)者,我想大都能理解,網(wǎng)上也有較多的關(guān)於此理論的闡述。之於Spring的AOP,在我的Blog之前的文章中也有總結(jié),見《Spring AOP Review》(http://www.tkk7.com/fastzch/archive/2006/08/15/63616.html)。
AOP之於IOC則要相對較為復(fù)雜一些,但是我們可以通過下面這個實際項目中的例子來看看AOP的威力。項目中常常都會有這樣的情況,每個業(yè)務(wù)處理的方法在進(jìn)入和退出時都需要記錄Debug信息,表示正常進(jìn)入和退出此方法。而我們一般的做法是在每個類的每個方法中都例用LOG4J的功能在此處打印一條LOG信息,而如果我們采用AOP的思想,則可以給所有這些方法做兩個切面,在所有這些方法執(zhí)行前和執(zhí)行後均記錄LOG信息。
我們可以試想一下,如果我們的項目有2000個類,每個文件平均8個方法,每個類得定義一個LOG變量,每條LOG記錄至少3行代碼,如:
if(DEBUGLOG.isDebugEnable()){
?DEBUGLOG.debug("*** class *** method begin.");
}
那麼總共需要2000*8*3*2+2000*1=98000行代碼來完成此功能,而如果我們采用AOP的思想可能僅僅需要上百行代碼足矣。這樣,我們不僅可以減少工作量,同時也可以減少出錯的機會,讓程序員更好的關(guān)注業(yè)務(wù)邏輯的處理。
好了,小小的功能便見識了其威力,再說多了有幫忙AOP打Ad.的嫌疑,書歸正傳。
對於AOP的基礎(chǔ)知識不想在此浪費精力,大多人都了解PointCut,Advice,aspect等概念在網(wǎng)上有太多的資料。
AspectJ的入門也不再冗述,安裝過Eclipse的AspectJ插件後便會有教程,同時大家也可以去看這篇文章:AspectJ初探(http://www.tkk7.com/pesome/archive/2005/08/03/9148.html)。
PointCut定義的格式如下:
pointcut name([parameters]):designator(ajoinpoint);
AspectJ有以下幾種連接點:
方法調(diào)用:pointcut name():call(public void method());
方法調(diào)用執(zhí)行:pointcut name():execution(public void method());
構(gòu)造方法調(diào)用:pointcut name():initialization(Object.new());
構(gòu)造方法調(diào)用執(zhí)行:pointcut name():execution(public Object.new());
字段獲?。簆ointcut name():get(public String Object.field);
字段設(shè)置:pointcut name():set(public String Object.field);
異常處理程序執(zhí)行:pointcut name():throws(Exception());
類初始化:
對象初始化:
注意:如果同時給某一個切面應(yīng)用方法調(diào)用和方法調(diào)用執(zhí)行兩種連接點時,方法調(diào)用在方法調(diào)用執(zhí)行之前執(zhí)行。
AspectJ連接點簽名方式:
方法調(diào)用執(zhí)行:<access_type><return_value><type>.<method_name>(parameter_list)
構(gòu)造方法調(diào)用執(zhí)行:<method_access_type><class_type.new>(<parameter_list>)[throws <exception>]
字段獲?。?lt;field_type><class_type>.<field_name>
字段設(shè)置:<field_type><class_type>.<field_name>
注意:如果字段是數(shù)組或是集合等類型時,並不是對數(shù)組每個單元的寫入就觸發(fā)連接點,而是只有當(dāng)一個值分配給變量的時候才會觸發(fā)連接點。
異常處理程序執(zhí)行:<exception type>
類/對象初始化:<method_access_type><method_name>(<parameter_list>)
類型名稱模式匹配:
*是一種能夠用來匹配所有類型的特定類型名稱。另外,*能夠匹配除“.”以外的零或多個符號。
所有的類的所有方法(有且僅有一個參數(shù)的方法)用下面這樣的模式來匹配:
call(* * *.*(*))
注意,這個模式只匹配帶有一個參數(shù)的方法,AspectJ中還有另外一個可用的通配符可以用來匹配任何字符序列,即“..”。那麼,
匹配所有類的所有方法的模式為:
call(* * *.*(..))
當(dāng)一個類是執(zhí)行階段中的目標(biāo)的時候,pointcut賦值符調(diào)用目標(biāo)將被觸發(fā)。這個時候連接點需要基於包中的具體類來定義。如:
target(com.test.ClassA)
如果要匹配com.test路徑下的任何類為目標(biāo),那麼可以使用下面的簽名:
target(com.test..*)
如果要匹配內(nèi)部類的類型,需要使用通配符“..”,如下:
target(com.test.*.*.*.*)
內(nèi)部類還可以是方法調(diào)用連接點簽名的一部分,如下:
call(private * com.test..*(..))
子類型模式:即匹配某一個類的所有子類,用“+”。如:
call (ObjectName+.new(..))
拋出模式:
call(* * *.*(..) throws * Exception *)
利用!可以否定某一異常匹配,如:call(* * *.*(..) throws ! BusiException)
前面所有定義的連接點都可以用邏輯操作符and(&&)、or(||)和not(!)組合起來。如:我們對A類層次中的子類型而不是A類本身感興趣,為了只匹配子類型中的構(gòu)造函數(shù),可以使用下面的連接點:
call((A+ && !A).new(..))
反射:
thisJoinPoint--該變量被綁定到連接點對象,並且有父類型org.aspectj.lang.JoinPoint。
其有效的方法如下:
String toString();--該方法返回連接點的一個字符串表示,一般為連接點的方法簽名。
String toShortString();--該方法返回連接點的一個短字符串表示,一般為帶類名的方法名。
String toLongString();--該方法返回連接點的一個擴展表示,一般為連接點的完整的方法簽名。
以下是我的樣例打印出來的結(jié)果:
??????toString():call(void test.Hello.sayHello(String))
??????toShortString():call(Hello.sayHello(..))
??????toLongString():call(public void test.Hello.sayHello(java.lang.String))
Object getThis();--該方法返回與該連接點關(guān)聯(lián)的當(dāng)前正在執(zhí)行的對象。此方法只有在連接點是調(diào)用執(zhí)行(execution)時才能得到該對象,如果在連接點是調(diào)用(call)的時候,得到的對象是null。
Object getTarget();--該方法返回與連接點關(guān)聯(lián)的目標(biāo)對象。目標(biāo)對象在方法調(diào)用接收或構(gòu)造方法調(diào)用接收的連接點上有效。
Object[] getArgs();--該方法將實際參數(shù)返回到邊接點上。
Signature getSignature();--該方法返回表示連接點簽名的對象。Signature對象包含幾個自身的方法:
??????String getName();該方法返回簽名的標(biāo)識符部分。
??????int getModifiers();該方法返回以整數(shù)表示的簽名的修飾符。其整數(shù)可以轉(zhuǎn)換成java.lang.reflect.Modifier類型,用來確定連接點所使用的訪問修飾符的類型。
SourceLocation getSourceLocation();--該方法與thisJointPoint對象關(guān)聯(lián),從表示連接點調(diào)用程序的SourceLocation類返回一個對象。如果沒有對象,則返回空。
String getKind();--該方法返回表示已觸發(fā)連接點類型的字符串。
StaticPart getStaticPart();--該方法返回上下文的靜態(tài)部分。
thisJoinPointStaticPart--該變量僅被綁定到有限的連接點對象,在使用的時候不需要分配內(nèi)存。
靜態(tài)部分可用的方法如下:
Signature getSignature();
SourceLocation getSourceLocation();
String getKind();
String toString();
String toShortString();
String toLongString();
這些方法同thisJoinPoint部分所列相同。
thisEnclosingJoinPointStaticPart--該變量僅被綁定到連接點對象的靜態(tài)部分,並且有父類型org.aspectj.lang.JoinPoint.StaticPart。
posted on 2006-12-11 21:18
Robin's Programming World 閱讀(2430)
評論(1) 編輯 收藏 所屬分類:
Java