在軟件開發(fā)中河绽,散步在應(yīng)用程序中多處的功能被稱為橫切關(guān)注點(diǎn)(cross-cutting concern)。通常來(lái)講這些橫切關(guān)注點(diǎn)從概念上講是與業(yè)務(wù)邏輯相分離的唉窃。把這些橫切關(guān)注點(diǎn)與業(yè)務(wù)邏輯分離正是面向切面編程(AOP)要做的事耙饰。
1.什么是面向切面編程
切面能夠幫助我們模塊化橫切關(guān)注點(diǎn)。橫切關(guān)注點(diǎn)可以被描述為影響應(yīng)用多處的功能纹份。下圖展現(xiàn)了被劃分為模塊的經(jīng)典應(yīng)用苟跪,每個(gè)模塊都有特定的業(yè)務(wù)邏輯,但這些模塊都需要特定的輔助功能蔓涧,如日志件已、緩存和事務(wù)管理。
面向切面編程提供了實(shí)現(xiàn)重用通用功能很好的方案元暴。在使用面向切面編程時(shí)篷扩,我們?nèi)匀辉谝粋€(gè)地方定義通用功能,但是可以通過(guò)聲明的方式定義這個(gè)功能以何種方式在何處使用茉盏,而無(wú)需修改受影響的類鉴未。橫切關(guān)注點(diǎn)可以被模塊化為固定的類枢冤,這些類稱為切面(aspect)。這樣做有兩個(gè)好處:首先每個(gè)關(guān)注點(diǎn)都集中于一個(gè)地方铜秆,而不是分散在代碼各處掏导;其次,服務(wù)模塊更簡(jiǎn)潔羽峰,因?yàn)樗麄冎话P(guān)注點(diǎn)(或核心功能)的代碼,其次要關(guān)注點(diǎn)的代碼被轉(zhuǎn)移到切面中了添瓷。
1.1定義AOP的術(shù)語(yǔ)
與大多數(shù)技術(shù)一樣AOP已經(jīng)形成了自己的術(shù)語(yǔ)梅屉。描述切面術(shù)語(yǔ)有通知(advice)、切點(diǎn)(pointcut)和連接點(diǎn)(joinpoint)鳞贷。
通知(Advice)
在AOP術(shù)語(yǔ)中坯汤,切面的工作被稱為通知。通知定義了切面是什么以及何時(shí)調(diào)用搀愧。Spring切面可以應(yīng)用5中類型的通知:
通知類型 | 描述 |
---|---|
前置通知(Before) | 在目標(biāo)方法調(diào)用前調(diào)用通知 |
后置通知(After) | 在目標(biāo)方法調(diào)用后調(diào)用通知 |
返回通知(After-returning) | 在目標(biāo)方法成功執(zhí)行之后調(diào)用通知 |
異常通知(After-throwing) | 在目標(biāo)方法發(fā)生異常時(shí)調(diào)用通知 |
環(huán)繞通知(Around) | 通知包裹目標(biāo)方法惰聂,在被通知的方法調(diào)用之前和調(diào)用之后執(zhí)行自定義的行為 |
連接點(diǎn)(Join point)
我們的應(yīng)用程序可能有數(shù)以萬(wàn)計(jì)的時(shí)機(jī)應(yīng)用通知,這些時(shí)機(jī)被稱為連接點(diǎn)咱筛。連接點(diǎn)是應(yīng)用程序執(zhí)行過(guò)程中能夠插入切面的一個(gè)點(diǎn)搓幌。這個(gè)點(diǎn)可以是調(diào)用方法、拋出異常迅箩、甚至修改一個(gè)字段時(shí)溉愁。切面代碼利用這些切入點(diǎn)插入到正常的流程中,并添加新的行為饲趋。
切點(diǎn)(Pointcut)
如果說(shuō)通知定義了“什么”和“何時(shí)”的話拐揭,那么切點(diǎn)就定義了“何處”,切點(diǎn)的定義會(huì)匹配通知所要織入的一個(gè)或多個(gè)連接點(diǎn)奕塑。我們常常使用明確的類和方法的名稱堂污,或使用正則表達(dá)式定義所匹配的類和方法的名稱來(lái)匹配連接點(diǎn)。有些AOP框架允許我們創(chuàng)建動(dòng)態(tài)連接點(diǎn)龄砰,可以根據(jù)運(yùn)行時(shí)的策略(比如方法的參數(shù)值)來(lái)決定是否應(yīng)用通知盟猖。
切面(Aspect)
切面是通知和切點(diǎn)的結(jié)合--他是什么,在何時(shí)换棚、何處完成其功能扒披。
引入(Introduction)
引入允許我們向現(xiàn)有的類中添加方法和屬性。例如我們創(chuàng)建了一個(gè)Auditable通知類圃泡,該類記錄對(duì)象最后以此修改的狀態(tài)碟案。只需要一個(gè)方法setLastModified(Date),和一個(gè)實(shí)例變量來(lái)保存這個(gè)狀態(tài)颇蜡。然后這個(gè)方法和變量就會(huì)被引入現(xiàn)有的類中价说,從而可以在不修改現(xiàn)有類的情況下為他們添加心得方法和狀態(tài)辆亏。
織入(Weaving)
織入就是將切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象的過(guò)程。切面在指定的連接點(diǎn)織入到目標(biāo)對(duì)象中鳖目。在目標(biāo)對(duì)象的生命周期中有多個(gè)點(diǎn)可以織入:
編譯器:切點(diǎn)在目標(biāo)對(duì)象類編譯時(shí)被織入扮叨。這種方式需要特殊的編譯器。AspectJ的織入編譯器就是以這種方式織入切面的领迈。
類加載期:切面在目標(biāo)類加載到JVM時(shí)被織入彻磁。這種方式需要特殊的類加載器(ClassLoader),它可以在目標(biāo)類被引入應(yīng)用之前增強(qiáng)該目標(biāo)類的字節(jié)碼狸捅。
運(yùn)行期:切面在應(yīng)用運(yùn)行的某個(gè)時(shí)刻被織入衷蜓。一般情況下,在織入切面時(shí)尘喝,AOP容器會(huì)為目標(biāo)對(duì)象動(dòng)態(tài)的創(chuàng)建一個(gè)代理對(duì)象磁浇。Spring AOP就是以這種方式被織入切面的。
在了解了AOP的這些術(shù)語(yǔ)后朽褪,就讓我們來(lái)看看AOP的這些概念在Spring中是如何實(shí)現(xiàn)的置吓。
2.Spring對(duì)AOP的支持
并不是所有的AOP框架都是相同的,他們?cè)谶B接點(diǎn)模型上可能有強(qiáng)弱之分缔赠。有些允許修飾符級(jí)別應(yīng)用通知衍锚,而另一些只支持與方法調(diào)用相關(guān)的連接點(diǎn)。他們織入切面的方式和時(shí)機(jī)也有所不同嗤堰。但無(wú)論如何构拳,創(chuàng)建切點(diǎn)來(lái)定義切面所織入的連接點(diǎn)是AOP框架的基本功能。
Spring提供了4種類型的AOP支持:
- 基于代理的經(jīng)典Spring AOP
- 純POJO切面
- @AspectJ注解驅(qū)動(dòng)的切面
- 注入式AspectJ切面(適用于Spring各版本)
前三種都是Spring AOP實(shí)現(xiàn)的變體梁棠,Spring AOP構(gòu)建在動(dòng)態(tài)代理基礎(chǔ)之上置森,因此,Spring 對(duì)AOP的支持局限于方法攔截符糊。下面我們來(lái)看看Spring AOP框架中一些關(guān)鍵的知識(shí)凫海。
2.1Spring通知是Java編寫的
Spring所創(chuàng)建的通知都是使用標(biāo)準(zhǔn)的Java類來(lái)編寫的。這樣我們可以使用與普通Java開發(fā)一樣的集成開發(fā)環(huán)境(IDE)來(lái)開發(fā)切面男娄。
2.2Spring在運(yùn)行時(shí)通知對(duì)象
Spring是在運(yùn)行期把切面織入到Spring管理的bean中行贪。代理類封裝了目標(biāo)類,并攔截被通知方法的調(diào)用模闲,再把調(diào)用轉(zhuǎn)發(fā)給真正的目標(biāo)bean建瘫。當(dāng)代理攔截到方法調(diào)用時(shí),再調(diào)用目標(biāo)bean方法之前尸折,會(huì)執(zhí)行切面邏輯啰脚。直到應(yīng)用真正需要被代理的bean時(shí),Spring才能創(chuàng)建代理對(duì)象实夹。因?yàn)镾pring運(yùn)行時(shí)才創(chuàng)建代理對(duì)象橄浓,所以不需要特殊的編譯器來(lái)織入Spring AOP的切面粒梦。
2.3Spring只支持方法級(jí)別的連接點(diǎn)
正如前面講述的,通過(guò)使用各種AOP方案可以支持多種連接點(diǎn)模型荸实。但Spring是基于動(dòng)態(tài)代理的匀们,所以Spring只支持方法連接點(diǎn)。這與一些其他的AOP框架是不同的准给,例如AspectJ和Jboss泄朴,除了方法切點(diǎn),他們還支持字段和構(gòu)造器接入點(diǎn)露氮。但是方法攔截器可以滿足絕大所數(shù)需求祖灰,如果我們需要使用方法攔截器之外的連接點(diǎn)可以利用Aspect來(lái)補(bǔ)充Spring AOP的功能。
對(duì)于什么是AOP以及Spring如何支持AOP的沦辙,我們現(xiàn)在已經(jīng)有了一個(gè)大致的了解。下節(jié)我們將會(huì)學(xué)習(xí)如何在Spring中創(chuàng)建切面讹剔,是不是很期待呢S脱丁!