一烈炭、Java平臺上AOP實現(xiàn)機制
1、jdk動態(tài)代理:利用攔截器(攔截器必須實現(xiàn)InvocationHanlder) + 反射機制? 生成一個實現(xiàn)代理接口的匿名類宝恶,在調(diào)用具體方法前調(diào)用InvokeHandler來處理符隙。要求目標(biāo)對象實現(xiàn)了接口。
2垫毙、動態(tài)字節(jié)碼增強:利用ASM/CGLIB霹疫,在程序運行期間,對動態(tài)構(gòu)建的字節(jié)碼文件生成相應(yīng)的子類综芥,將橫切邏輯加入自類中丽蝎。不需要目標(biāo)對象實現(xiàn)接口,但擴展類以及方法不能為final膀藐。
????????Spring AOP在無法采用動態(tài)代理機制進行AOP功能擴展的時候屠阻,會使用CGLIB庫的動態(tài)字節(jié)碼增強支持來實現(xiàn)AOP的功能擴展。
????????在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>強制使用cglib额各。
3国觉、java代碼生成
4、自定義類加載器
二虾啦、基本概念
1麻诀、JointPoint(連接點/織入點):在系統(tǒng)運行之前,AOP的功能模塊都需要織入到OOP的功能模塊中傲醉。所以蝇闭,要進行這種織入過程, 我們需要知道在系統(tǒng)的哪些執(zhí)行點上進行織入操作,這些將要在其之上進行織入操作的系統(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進行區(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)造方法進行初始化的時點撵渡,也就是圖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所在方法名稱、正則表達式尘执、使用特定的Pointcut表述語言舍哄。
3、Advice(通知誊锭、增強處理):按照Advice在Joinpoint位置執(zhí)行時機的差異或者完成功能的不同表悬,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還可以細分為以下三種冠息。
? ? ????????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í)行時機可以基本如圖3所示。
3)Around Advice
AOP Alliance屬下的AOP實現(xiàn)大都采用攔截器(Interceptor)的叫法惑申,但完成的功能是一樣的具伍。Around Advice對附加其上的Joinpoint進行“包裹”,可以在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í)行時機來區(qū)分的舒萎,而是根據(jù)它可以完成的功能而區(qū)別于其他Advice類型。?
????????Introduction可以為原有的對象添加新的特性或者行為咧栗,這就好像你是一個普通公民逆甜,當(dāng)讓你穿軍裝,帶軍帽致板,添加了軍人類型的Introduction之后交煞,你就擁有軍人的特性或者行為。
4斟或、Aspect(切面):Aspect是對系統(tǒng)中的橫切關(guān)注點邏輯進行模塊化封裝的AOP概念實體素征。通常情況下,Aspect可以包含多個Pointcut以及相關(guān)Advice定義。