心情沒(méi)法不沉重患雇,被問(wèn)到AOP是什么跃脊?AOP原理是什么?我竟然張大了嘴巴苛吱,說(shuō)不出來(lái)酪术!對(duì)于一個(gè)程序員的打擊,還能有比這更大的嗎?我沒(méi)臉說(shuō)我是個(gè)寫代碼的绘雁,我也沒(méi)臉說(shuō)我是程序員橡疼。
AOP是什么?
定義
AOP庐舟,面向切面編程欣除,是對(duì)OOP的補(bǔ)充。從網(wǎng)上看到的一句話:這種在運(yùn)行時(shí)挪略,動(dòng)態(tài)的將代碼切入到類的指定方法或者指定位置上的編程思想历帚,就是面向切面的編程。
這是其中的一種方式杠娱,在運(yùn)行時(shí)動(dòng)態(tài)添加挽牢。還有另外一種是在編譯代碼的時(shí)候,將代碼切入到指定的方法或者位置上去墨辛,這是靜態(tài)添加的方式卓研。
使用
我們?cè)趯?shí)際的業(yè)務(wù)中都會(huì)有一些公共邏輯,比如日志的記錄睹簇,事務(wù)的管理等等奏赘,而如果每次都把日志和事務(wù)的代碼手動(dòng)寫到業(yè)務(wù)邏輯前后,重復(fù)代碼就相當(dāng)可怕太惠,而如果這些額外代碼有修改磨淌,必須要每個(gè)都修改,這是相當(dāng)不明智的凿渊。AOP可以幫我們解決這些問(wèn)題梁只。
實(shí)現(xiàn)
其實(shí)AOP本身并不能幫我們解決那些問(wèn)題,AOP就是一種思想埃脏,而幫我們解決的是具體的AOP的實(shí)現(xiàn)搪锣,比如aspectj,jboss AOP彩掐,以及我們最熟悉的Spring AOP构舟,Spring AOP在Spring1.0的時(shí)候是自己實(shí)現(xiàn)的AOP框架,在2.0之后就開(kāi)始集成了aspectj《掠模現(xiàn)在我們所說(shuō)的Spring AOP就是Spring加Aspectj這種方式狗超。
AOP的相關(guān)概念
對(duì)于AOP中相關(guān)的概念,我們接觸更多的還是Spring AOP朴下,這里主要是以Spring AOP的概念來(lái)說(shuō)明:
- Aspect努咐,切面,一個(gè)關(guān)注點(diǎn)的模塊化殴胧,這個(gè)關(guān)注點(diǎn)可能會(huì)橫切多個(gè)對(duì)象渗稍。
- JoinPoint,連接點(diǎn),在程序執(zhí)行過(guò)程中某個(gè)特定的點(diǎn)竿屹,比如某方法調(diào)用的時(shí)候或者處理異常的時(shí)候音五。在Spring AOP中,一個(gè)連接點(diǎn)總是表示一個(gè)方法的執(zhí)行羔沙。
- Advice,通知厨钻,在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作扼雏。
- 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í))蝴蜓。切入點(diǎn)表達(dá)式如何和連接點(diǎn)匹配是AOP的核心:Spring缺省使用AspectJ切入點(diǎn)語(yǔ)法。
上面是關(guān)于AOP中幾個(gè)基本概念的定義俺猿,下面看下有關(guān)我們使用時(shí)的一些概念:
- Target Object茎匠,目標(biāo)對(duì)象,被一個(gè)或者多個(gè)切面所通知的對(duì)象押袍。也就是我們業(yè)務(wù)中實(shí)際要進(jìn)行增強(qiáng)的業(yè)務(wù)對(duì)象诵冒。
- AOP Proxy,AOP代理谊惭,AOP框架創(chuàng)建的對(duì)象汽馋。也就是被增強(qiáng)之后的對(duì)象。
- Weaving圈盔,織入豹芯,把切面連接到其它的應(yīng)用程序類型或者對(duì)象上,并創(chuàng)建一個(gè)被通知的對(duì)象驱敲。就是把切面作用到目標(biāo)對(duì)象铁蹈,然后產(chǎn)生一個(gè)代理對(duì)象的過(guò)程。
還有另外一個(gè)概念癌佩,是給類聲明額外方法的概念:
- Introduction木缝,引介,用來(lái)給一個(gè)類型聲明額外的方法或?qū)傩晕д蕖>褪俏铱梢圆挥脤?shí)現(xiàn)另外一個(gè)接口我碟,就能使用那個(gè)接口的方法。
通知類型
Advice是通知姚建,也就是在切面的某個(gè)連接點(diǎn)上要執(zhí)行的動(dòng)作矫俺,也就是我們要編寫的增強(qiáng)功能的代碼。通知也分為好幾種類型,分別有不同作用:
- 前置通知(Before advice):在某連接點(diǎn)之前執(zhí)行的通知厘托,但這個(gè)通知不能阻止連接點(diǎn)之前的執(zhí)行流程(除非它拋出一個(gè)異常)友雳。
- 后置通知(After returning advice):在某連接點(diǎn)正常完成后執(zhí)行的通知:例如,一個(gè)方法沒(méi)有拋出任何異常铅匹,正常返回押赊。
- 異常通知(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)用前后完成自定義的行為神帅。它也會(huì)選擇是否繼續(xù)執(zhí)行連接點(diǎn)或直接返回它自己的返回值或拋出異常來(lái)結(jié)束執(zhí)行。
AOP原理
上面說(shuō)到了AOP可以在編譯時(shí)候?qū)⒋a織入到指定的方法或者屬性上萌抵,或者在運(yùn)行的時(shí)候動(dòng)態(tài)的將代碼切入到指定的方法或者屬性中找御,這描述了AOP應(yīng)該要做的事情,其實(shí)也基本算是它的原理了绍填,AOP實(shí)現(xiàn)的關(guān)鍵就是創(chuàng)建AOP代理霎桅,代理有靜態(tài)代理和動(dòng)態(tài)代理之分,其中aspectj為靜態(tài)代理讨永,Spring AOP是動(dòng)態(tài)代理哆档,這里把靜態(tài)和運(yùn)行時(shí)動(dòng)態(tài)的分開(kāi)說(shuō)。
AspectJ編譯時(shí)增強(qiáng)
aspectj編譯時(shí)增強(qiáng)住闯,既是靜態(tài)代理增強(qiáng)瓜浸,也就是會(huì)在編譯階段生成代理,將代碼織入到Java的字節(jié)碼中去比原。
Spring AOP的運(yùn)行時(shí)增強(qiáng)
Spring AOP是基于代理機(jī)制的插佛,并且Spring AOP使用的是動(dòng)態(tài)代理增強(qiáng),動(dòng)態(tài)代理不會(huì)改變類的字節(jié)碼量窘,而是動(dòng)態(tài)的生成代理對(duì)象雇寇。Spring AOP的動(dòng)態(tài)代理機(jī)制有兩種方式:JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理。
JDK動(dòng)態(tài)代理
JDK動(dòng)態(tài)代理需要被代理的類必須實(shí)現(xiàn)一個(gè)接口蚌铜,通過(guò)使用反射來(lái)接受被代理的類锨侯。
CGLIB動(dòng)態(tài)代理
CGLIB動(dòng)態(tài)代理可以不用需要被代理類必須實(shí)現(xiàn)接口,被代理類可以是一個(gè)類冬殃。
Spring AOP
上面說(shuō)到了Spring AOP中使用的是動(dòng)態(tài)代理機(jī)制囚痴,同時(shí)也分為兩種代理機(jī)制:JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理,這可以在源碼中看到审葬,在DefaultAopProxyFactory的createAopProxy中可看到:
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
//可以看到這里有條件是沒(méi)有實(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);
}
}
對(duì)于接口的代理使用的JDK動(dòng)態(tài)代理深滚,而對(duì)于類的代理使用的是CGLIB動(dòng)態(tài)代理奕谭。
AOP的使用場(chǎng)景
AOP適用于具有橫切邏輯的應(yīng)用,比如性能監(jiān)控痴荐,日志記錄血柳,緩存,事務(wù)管理生兆,訪問(wèn)控制等难捌。
有關(guān)Spring AOP的例子可以參考Spring中AOP的配置從1.0到5.0的演進(jìn),這里有具體的配置鸦难。