0. AOP是什么?
AOP,面向切面編程,是對OOP的補(bǔ)充。面向切面編程有好幾種方式,可以在編譯時(shí)候織入,也可以在運(yùn)行時(shí)候織入,將代碼切入到指定的方法或者位置上去。一般來說有以下幾種方式:
AspectJ編譯時(shí)增強(qiáng)
aspectj編譯時(shí)增強(qiáng),既是靜態(tài)代理增強(qiáng),也就是會在編譯階段生成代理,將代碼織入到Java的字節(jié)碼中去。
Spring AOP的運(yùn)行時(shí)增強(qiáng)
Spring AOP是基于代理機(jī)制的,并且Spring AOP使用的是動態(tài)代理增強(qiáng),動態(tài)代理不會改變類的字節(jié)碼,而是動態(tài)的生成代理對象。Spring AOP的動態(tài)代理機(jī)制有兩種方式:JDK動態(tài)代理和CGLIB動態(tài)代理。
JDK動態(tài)代理
JDK動態(tài)代理需要被代理的類必須實(shí)現(xiàn)一個(gè)接口,通過使用反射來接受被代理的類。
CGLIB動態(tài)代理
CGLIB動態(tài)代理可以不用需要被代理類必須實(shí)現(xiàn)接口,被代理類可以是一個(gè)類。
Spring AOP
上面說到了Spring AOP中使用的是動態(tài)代理機(jī)制,同時(shí)也分為兩種代理機(jī)制:JDK動態(tài)代理和CGLIB動態(tài)代理,這可以在源碼中看到,在DefaultAopProxyFactory的createAopProxy中可看到:
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
//可以看到這里有條件是沒有實(shí)現(xiàn)接口
boolean useCglib = advisedSupport.getOptimize()
|| advisedSupport.getProxyTargetClass()
|| advisedSupport.getProxiedInterfaces().length == 0;
if (useCglib) {
return CglibProxyFactory.createCglibProxy(advisedSupport);
}
else {
// Depends on whether we have expose proxy or frozen or static ts
return new JdkDynamicAopProxy(advisedSupport);
}
}
對于接口的代理使用的JDK動態(tài)代理,而對于類的代理使用的是CGLIB動態(tài)代理。
AOP的相關(guān)概念
1. AOP的相關(guān)概念
- Aspect,切面,一個(gè)關(guān)注點(diǎn)的模塊化,這個(gè)關(guān)注點(diǎn)可能會橫切多個(gè)對象。
- JoinPoint(連接點(diǎn)),程序中可能作為代碼注入目標(biāo)的特定的點(diǎn)。在AspectJ中可以作為JoinPoints的地方包括:
| JoinPoints | 說明 | 示例 |
|---|---|---|
| method call | 函數(shù)調(diào)用 | 比如調(diào)用Log.e(),這是一處Joint point |
| method execution | 函數(shù)執(zhí)行 | 比如Log.e()的執(zhí)行內(nèi)部,是一處Joint Point |
| constructor call | 構(gòu)造函數(shù)調(diào)用 | 與方法的調(diào)用類型 |
| constructor executor | 構(gòu)造函數(shù)執(zhí)行 | 與方法的執(zhí)行執(zhí)行 |
| field get | 獲取某個(gè)變量 | |
| field set | 設(shè)置某個(gè)變量 | |
| static initialization | 類初始化 | |
| initialization | object在構(gòu)造函數(shù)中做的一些工作 | |
| handler | 異常處理 | 對應(yīng)try-catch()中,對應(yīng)的catch塊內(nèi)的執(zhí)行 |
Advice,通知類型,在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動作。其實(shí)就是注入到class文件中的代碼片。典型的 Advice 類型有 before、after 和 around,分別表示在目標(biāo)方法執(zhí)行之前、執(zhí)行后和完全替代目標(biāo)方法執(zhí)行的代碼:
前置通知(Before advice):在某連接點(diǎn)之前執(zhí)行的通知,但這個(gè)通知不能阻止連接點(diǎn)之前的執(zhí)行流程(除非它拋出一個(gè)異常)。
后置通知(After returning advice):在某連接點(diǎn)正常完成后執(zhí)行的通知:例如,一個(gè)方法沒有拋出任何異常,正常返回。
異常通知(After throwing advice):在方法拋出異常退出時(shí)執(zhí)行的通知。
最終通知(After (finally) advice):當(dāng)某連接點(diǎn)退出的時(shí)候執(zhí)行的通知(不論是正常返回還是異常退出)。
環(huán)繞通知(Around Advice):包圍一個(gè)連接點(diǎn)的通知,如方法調(diào)用。這是最強(qiáng)大的一種通知類型。環(huán)繞通知可以在方法調(diào)用前后完成自定義的行為。它也會選擇是否繼續(xù)執(zhí)行連接點(diǎn)或直接返回它自己的返回值或拋出異常來結(jié)束執(zhí)行。Pointcut,切點(diǎn),匹配連接點(diǎn)的斷言。通知和一個(gè)切入點(diǎn)表達(dá)式關(guān)聯(lián),并在滿足這個(gè)切入點(diǎn)的連接點(diǎn)上運(yùn)行(例如,當(dāng)執(zhí)行某個(gè)特定名稱的方法時(shí))。
Weaving,注入代碼(advices)到目標(biāo)位置(joint points)的過程