一、Java平臺上AOP實現(xiàn)機(jī)制
1、jdk動態(tài)代理:利用攔截器(攔截器必須實現(xiàn)InvocationHanlder) + 反射機(jī)制? 生成一個實現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來處理。要求目標(biāo)對象實現(xiàn)了接口。
2、動態(tài)字節(jié)碼增強(qiáng):利用ASM/CGLIB,在程序運行期間,對動態(tài)構(gòu)建的字節(jié)碼文件生成相應(yīng)的子類,將橫切邏輯加入自類中。不需要目標(biāo)對象實現(xiàn)接口,但擴(kuò)展類以及方法不能為final。
????????Spring AOP在無法采用動態(tài)代理機(jī)制進(jìn)行AOP功能擴(kuò)展的時候,會使用CGLIB庫的動態(tài)字節(jié)碼增強(qiáng)支持來實現(xiàn)AOP的功能擴(kuò)展。
????????在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>強(qiáng)制使用cglib。
3、java代碼生成
4、自定義類加載器
二、基本概念
1、JointPoint(連接點/織入點):在系統(tǒng)運行之前,AOP的功能模塊都需要織入到OOP的功能模塊中。所以,要進(jìn)行這種織入過程, 我們需要知道在系統(tǒng)的哪些執(zhí)行點上進(jìn)行織入操作,這些將要在其之上進(jìn)行織入操作的系統(tǒng)執(zhí)行點就 稱之為Joinpoint。

常用的JointPoint類型:
1)方法調(diào)用(Method Call)。當(dāng)某個方法被調(diào)用的時候所處的程序執(zhí)行點,上圖1中的后面三個“圓 圈”所標(biāo)記的時點都屬于這種類型。
2)方法調(diào)用執(zhí)行(Method Call execution) 。稱之為方法執(zhí)行或許更簡潔,該Joinpoint類型代表的是某個方法內(nèi)部執(zhí)行開始時點,應(yīng)該與方法調(diào)用類型的Joinpoint進(jìn)行區(qū)分。

方法調(diào)用(method call)是在調(diào)用對象上的執(zhí)行點,而方法執(zhí)行(method execution)則是在被調(diào)用到的方法邏輯執(zhí)行的時點。對于同一對象,方法調(diào)用要先于方法執(zhí)行。
構(gòu)造方法調(diào)用(Constructor Call)。程序執(zhí)行過程中對某個對象調(diào)用其構(gòu)造方法進(jìn)行初始化的時點,也就是圖1中如下代碼所在的執(zhí)行點。
HelioBean helloBean = new HelloBean( "Hello! ");
構(gòu)造方法執(zhí)行(Constructor Call Execution)。構(gòu)造方法執(zhí)行和構(gòu)造方法調(diào)用之間的關(guān)系類似于方法執(zhí)行和方法調(diào)用之間的關(guān)系,指的是某個對象構(gòu)造方法內(nèi)部執(zhí)行的開始時點。
字段設(shè)置(FieldSet)。對象的某個屬性通過setter方法被設(shè)置或者直接被設(shè)置的時點。該Joinpoint 的本質(zhì)是對象的屬性被設(shè)置,而通過setter方法設(shè)置還是直接設(shè)置觸發(fā)的時點是相同的。
字段獲取(FieldGet)。相對于字段設(shè).置型的Joinpoint,字段獲取型的Joinpoint,對應(yīng)的是某個對象相應(yīng)屬性被訪問的時點。可以通過getter方法訪問,當(dāng)然也可以直接訪問。
異常處理執(zhí)行(Exception Handler Execution該類型的Joinpoin說t應(yīng)程序執(zhí)行過程中,在某些類型異常拋出后,對應(yīng)的異常處理邏輯執(zhí)行的時點。
類初始化(Class initialization)?類初始化型的Joinpoint,指的是類中某些靜態(tài)類型或者靜態(tài)塊的初始化時點。比如,如下代碼中的log4j初始化位置即屬于該類型Joinpoint對應(yīng)位置的一種。
class FooBar{
????????static{
????????????//初始化Iog4j?
????????????BasicConfigurator.configure();
? ??????}
????????private Foo attribute;
????????//其他方法定義
}
2、Pointcut(切點):Pointcui概念代表的是Joinpoint的表述方式。將橫切邏輯織入當(dāng)前系統(tǒng)的過程中,需要參照Pointcut 規(guī)定的Joinpoint信息,才可以知道應(yīng)該往系統(tǒng)的哪些Joinpoint上織入橫切邏輯
????????以圖1中的helloBean.helloMethod()所在位置的Joinpoint為例,該方法在程序中兩個地方被調(diào)用,而我們系統(tǒng)在這兩個地方都要織入相應(yīng)的橫切邏輯,那么,我們就可以通過以下Pointcut表述來指定這兩個Joinpoint:系統(tǒng)中HelloBean類的helloMechod()方法被調(diào)用的所有Joinpoint。
????????Pointcut的表述方式:直接指定Joinpoint所在方法名稱、正則表達(dá)式、使用特定的Pointcut表述語言。
3、Advice(通知、增強(qiáng)處理):按照Advice在Joinpoint位置執(zhí)行時機(jī)的差異或者完成功能的不同,Advice可以分成多種具體形式。
1)Before Advice
Before Advice是在Joinpoint指定位置之前執(zhí)行的Advice類型。通常,它不會中斷程序執(zhí)行流程,但如果必要,可以通過在Before Advice中拋出異常的方式來中斷當(dāng)前程序流程。如果當(dāng)前Before Advice 將被織入到方法執(zhí)行類型的Joinpoint,那么這個Before Advice就會先于方法執(zhí)行而執(zhí)行。
????????通常,可以使用Before Advice做一些系統(tǒng)的初始化工作,比如設(shè)置系統(tǒng)初始值,獲取必要系統(tǒng)資源等。當(dāng)然,并非就限于這些情況。如果要用Before Advice來封裝安全檢查的邏輯,也不是不可以的,但通常情況下,我們會使用另一種形式的Advice。
2)After Advice
顧名思義,After Advice就是在相應(yīng)連接點之后執(zhí)行的Advice類型,但該類型的Advice還可以細(xì)分為以下三種。
? ? ????????After returning Advice,只有當(dāng)前Joinpoint處執(zhí)行流程正常完成后,After returning Advice才會執(zhí)行。比如方法執(zhí)行正常返回而沒有拋出異常。?
????????????After throwing Advice, 又稱Throws Advice,只有在當(dāng)前Joinpoint執(zhí)行過程中拋出異常的情況下,才會執(zhí)行。比如某個方法執(zhí)行類型的Joinpoint拋出某異常而沒有正常返回。
????????????After Advice ,或許叫After (Finally) Advice更為確切,該類型Advice不管Joinpoint處執(zhí)行流程是正常終了還是拋出異常都會執(zhí)行,就好像Java中的finally塊一樣。
如果以方法執(zhí)行類型的Joinpoint為例,我們的各種Advice的執(zhí)行時機(jī)可以基本如圖3所示。

3)Around Advice
AOP Alliance屬下的AOP實現(xiàn)大都采用攔截器(Interceptor)的叫法,但完成的功能是一樣的。Around Advice對附加其上的Joinpoint進(jìn)行“包裹”,可以在Joinpoint之前和之后都指定相應(yīng)的邏輯,甚至于中斷或者忽略Joinpoint處原來程序流程的執(zhí)行。
Around Advice的行為可以因為你而發(fā)生改變。呵呵,就好像這“居心叵測”的“叵”字,中間的 那一 “口 ”就是Joinpoint,上下一橫就好像是要執(zhí)行的邏輯。當(dāng)我們只是希望在Joinpoint之前和之后執(zhí)行橫切邏輯,而忽略原來Joinpoint處的邏輯執(zhí)行的時候,就是居心“叵”測了。而正常情況下,Around Advice應(yīng)該像一個“巨"字,我們執(zhí)行完Joinpoint之前的邏輯之后,會接著走Joinpoint,然后才是Joinpoint 之后的邏輯。
既然Around Adviceoj以在Joinpoin之前和之后都能執(zhí)行相應(yīng)的邏輯,那么,它自然可以完成Before Advice和After Advice的功能。不過,通常情況下,還是應(yīng)該根據(jù)場景選用更為具體的Advice類型。
Around Advice應(yīng)用場景非常廣泛,我想大家對于J2EE中的Servlet規(guī)范提供的Filter功能應(yīng)該很熟悉吧。實際上,它就是Around Advice的一種體現(xiàn)。使用它,我們就可以完成“資源初始化”、“安全檢 查”之類橫切系統(tǒng)的關(guān)注點了。
4)Introduction
????????在Aspect!中稱Inter-Type Declaration,在JBoss AOP中稱Mix-in.都指的是這同一種類型的Advice. 與之前的幾種Advice類型不同,Introduction不是根據(jù)橫切邏輯在Joinpoint處的執(zhí)行時機(jī)來區(qū)分的,而是根據(jù)它可以完成的功能而區(qū)別于其他Advice類型。?
????????Introduction可以為原有的對象添加新的特性或者行為,這就好像你是一個普通公民,當(dāng)讓你穿軍裝,帶軍帽,添加了軍人類型的Introduction之后,你就擁有軍人的特性或者行為。
4、Aspect(切面):Aspect是對系統(tǒng)中的橫切關(guān)注點邏輯進(jìn)行模塊化封裝的AOP概念實體。通常情況下,Aspect可以包含多個Pointcut以及相關(guān)Advice定義。
