Spring(七)Spring AOP

一、AOP 簡(jiǎn)介

AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方法論, 是對(duì)傳統(tǒng) OOP(Object-Oriented Programming, 面向?qū)ο缶幊? 的補(bǔ)充.

AOP 的主要編程對(duì)象是切面(aspect), 而切面模塊化橫切關(guān)注點(diǎn).

在應(yīng)用 AOP 編程時(shí), 仍然需要定義公共功能, 但可以明確的定義這個(gè)功能在哪里, 以什么方式應(yīng)用, 并且不必修改受影響的類. 這樣一來(lái)橫切關(guān)注點(diǎn)就被模塊化到特殊的對(duì)象(切面)里.

AOP 的好處:

①窥妇、每個(gè)事物邏輯位于一個(gè)位置, 代碼不分散, 便于維護(hù)和升級(jí)

②、業(yè)務(wù)模塊更簡(jiǎn)潔, 只包含核心業(yè)務(wù)代碼.

二魏身、AOP 術(shù)語(yǔ)

切面(Aspect): 橫切關(guān)注點(diǎn)(跨越應(yīng)用程序多個(gè)模塊的功能)被模塊化的特殊對(duì)象

通知(Advice):切面必須要完成的工作

目標(biāo)(Target):被通知的對(duì)象

代理(Proxy):向目標(biāo)對(duì)象應(yīng)用通知之后創(chuàng)建的對(duì)象

連接點(diǎn)(Joinpoint):程序執(zhí)行的某個(gè)特定位置:如類某個(gè)方法調(diào)用前橱赠、調(diào)用后器联、方法拋出異常后等。連接點(diǎn)由兩個(gè)信息確定:方法表示的程序執(zhí)行點(diǎn)遍烦;相對(duì)點(diǎn)表示的方位俭嘁。例如 ArithmethicCalculator#add() 方法執(zhí)行前的連接點(diǎn),執(zhí)行點(diǎn)為 ArithmethicCalculator#add()服猪; 方位為該方法執(zhí)行前的位置

切點(diǎn)(pointcut):每個(gè)類都擁有多個(gè)連接點(diǎn):例如 ArithmethicCalculator 的所有方法實(shí)際上都是連接點(diǎn)供填,即連接點(diǎn)是程序類中客觀存在的事務(wù)。AOP 通過(guò)切點(diǎn)定位到特定的連接點(diǎn)罢猪。類比:連接點(diǎn)相當(dāng)于數(shù)據(jù)庫(kù)中的記錄近她,切點(diǎn)相當(dāng)于查詢條件。切點(diǎn)和連接點(diǎn)不是一對(duì)一的關(guān)系膳帕,一個(gè)切點(diǎn)匹配多個(gè)連接點(diǎn)粘捎,切點(diǎn)通過(guò) org.springframework.aop.Pointcut 接口進(jìn)行描述,它使用類和方法作為連接點(diǎn)的查詢條件危彩。

AspectJ:Java 社區(qū)里最完整最流行的 AOP 框架.

在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

三攒磨、在 Spring 中啟用 AspectJ 注解支持

(1)要在 Spring 應(yīng)用中使用 AspectJ 注解, 必須在 classpath 下包含 AspectJ 類庫(kù):

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

spring-aop-4.0.0.RELEASE.jar

spring-aspects-4.0.0.RELEASE.jar

(2)將 aop Schema 添加到<beans>根元素中.

(3)要在 Spring IOC 容器中啟用 AspectJ 注解支持, 只要在 Bean 配置文件中定義一個(gè)空的 XML 元素<aop:aspectj-autoproxy>

(4)當(dāng) Spring IOC 容器偵測(cè)到 Bean 配置文件中的 <aop:aspectj-autoproxy>元素時(shí), 會(huì)自動(dòng)為與 AspectJ 切面匹配的 Bean 創(chuàng)建代理.

四、用 AspectJ 注解聲明切面

要在 Spring 中聲明 AspectJ 切面, 只需要在 IOC 容器中將切面聲明為 Bean 實(shí)例. 當(dāng)在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就會(huì)為那些與 AspectJ 切面相匹配的 Bean 創(chuàng)建代理.

在 AspectJ 注解中, 切面只是一個(gè)帶有 @Aspect 注解的 Java 類.

通知是標(biāo)注有某種注解的簡(jiǎn)單的 Java 方法.

AspectJ 支持 5 種類型的通知注解:

@Before:前置通知, 在方法執(zhí)行之前執(zhí)行

@After:后置通知, 在方法執(zhí)行之后執(zhí)行

@AfterRunning:返回通知, 在方法返回結(jié)果之后執(zhí)行

@AfterThrowing:異常通知, 在方法拋出異常之后

@Around:環(huán)繞通知, 圍繞著方法執(zhí)行

五汤徽、前置通知和后置通知

(1)導(dǎo)入包

(2)新建一個(gè)接口和一個(gè)實(shí)現(xiàn)類

(3)配置自動(dòng)掃描的包

(4)測(cè)試

(5)通過(guò)Aspect聲明切面

(6)在bean的配置文件中配置使AspectJ的注解起作用

(7)測(cè)試是否生效

六娩缰、利用方法簽名編寫 AspectJ 切入點(diǎn)表達(dá)式

最典型的切入點(diǎn)表達(dá)式時(shí)根據(jù)方法的簽名來(lái)匹配各種方法:

execution * com.liqc.spring.ArithmeticCalculator.*(..):匹配 ArithmeticCalculator 中聲明的所有方法,第一個(gè) * 代表任意修飾符及任意返回值,第二個(gè) * 代表任意方法谒府, .. 匹配任意數(shù)量的參數(shù)拼坎,若目標(biāo)類與接口與該切面在同一個(gè)包中梧奢,可以省略包名。

execution public * ArithmeticCalculator.*(..):匹配 ArithmeticCalculator 接口的所有公有方法演痒。

execution public double ArithmeticCalculator.*(..):匹配 ArithmeticCalculator 中返回 double 類型數(shù)值的方法。

execution public double ArithmeticCalculator.*(double, ..):匹配第一個(gè)參數(shù)為 double 類型的方法趋惨, .. 匹配任意數(shù)量任意類型的參數(shù)鸟顺。

execution public double ArithmeticCalculator.*(double, double):匹配參數(shù)類型為 double, double 類型的方法。

合并切入點(diǎn)表達(dá)式:

在 AspectJ 中器虾,切入點(diǎn)表達(dá)式可以通過(guò)操作符 &&讯嫂,||,! 結(jié)合起來(lái)兆沙。

七欧芽、讓通知訪問(wèn)當(dāng)前連接點(diǎn)的細(xì)節(jié)

可以在通知方法中聲明一個(gè)類型為 JoinPoint 的參數(shù),然后就能訪問(wèn)鏈接細(xì)節(jié). 如方法名稱和參數(shù)值葛圃。

八千扔、返回通知

(1)無(wú)論連接點(diǎn)是正常返回還是拋出異常,后置通知都會(huì)執(zhí)行库正, 如果只想在連接點(diǎn)返回的時(shí)候記錄日志曲楚,應(yīng)使用返回通知代替后置通知。

(2)在返回通知中訪問(wèn)連接點(diǎn)的返回值:

在返回通知中褥符,只要將 returning 屬性添加到 @AfterReturning 注解中龙誊,就可以訪問(wèn)連接點(diǎn)的返回值。該屬性的值即為用來(lái)傳入返回值的參數(shù)名稱喷楣。

必須在通知方法的簽名中添加一個(gè)同名參數(shù)趟大,在運(yùn)行時(shí),Spring AOP 會(huì)通過(guò)這個(gè)參數(shù)傳遞返回值铣焊。

原始的切點(diǎn)表達(dá)式需要出現(xiàn)在 pointcut 屬性中逊朽。

九、異常通知

只在連接點(diǎn)拋出異常時(shí)才執(zhí)行異常通知

將 throwing 屬性添加到 @AfterThrowing 注解中, 也可以訪問(wèn)連接點(diǎn)拋出的異常. Throwable 是所有錯(cuò)誤和異常類的超類. 所以在異常通知方法可以捕獲到任何錯(cuò)誤和異常.

如果只對(duì)某種特殊的異常類型感興趣, 可以將參數(shù)聲明為其他異常的參數(shù)類型. 然后通知就只在拋出這個(gè)類型及其子類的異常時(shí)才被執(zhí)行.

十曲伊、環(huán)繞通知

環(huán)繞通知是所有通知類型中功能最為強(qiáng)大的, 能夠全面地控制連接點(diǎn). 甚至可以控制是否執(zhí)行連接點(diǎn).

對(duì)于環(huán)繞通知來(lái)說(shuō), 連接點(diǎn)的參數(shù)類型必須是 ProceedingJoinPoint . 它是 JoinPoint 的子接口, 允許控制何時(shí)執(zhí)行, 是否執(zhí)行連接點(diǎn).

在環(huán)繞通知中需要明確調(diào)用 ProceedingJoinPoint 的 proceed() 方法來(lái)執(zhí)行被代理的方法. 如果忘記這樣做就會(huì)導(dǎo)致通知被執(zhí)行了, 但目標(biāo)方法沒(méi)有被執(zhí)行.

注意: 環(huán)繞通知的方法需要返回目標(biāo)方法執(zhí)行之后的結(jié)果, 即調(diào)用 joinPoint.proceed(); 的返回值, 否則會(huì)出現(xiàn)空指針異常

十一惋耙、指定切面的優(yōu)先級(jí)

在同一個(gè)連接點(diǎn)上應(yīng)用不止一個(gè)切面時(shí), 除非明確指定, 否則它們的優(yōu)先級(jí)是不確定的.

切面的優(yōu)先級(jí)可以通過(guò)實(shí)現(xiàn) Ordered 接口或利用 @Order 注解指定.

實(shí)現(xiàn) Ordered 接口, getOrder() 方法的返回值越小, 優(yōu)先級(jí)越高.

若使用 @Order 注解, 序號(hào)出現(xiàn)在注解中,值越小優(yōu)先級(jí)越高

十二熊昌、重用切入點(diǎn)定義

在編寫 AspectJ 切面時(shí), 可以直接在通知注解中書寫切入點(diǎn)表達(dá)式. 但同一個(gè)切點(diǎn)表達(dá)式可能會(huì)在多個(gè)通知中重復(fù)出現(xiàn).

在 AspectJ 切面中, 可以通過(guò) @Pointcut 注解將一個(gè)切入點(diǎn)聲明成簡(jiǎn)單的方法. 切入點(diǎn)的方法體通常是空的, 因?yàn)閷⑶腥朦c(diǎn)定義與應(yīng)用程序邏輯混在一起是不合理的.

切入點(diǎn)方法的訪問(wèn)控制符同時(shí)也控制著這個(gè)切入點(diǎn)的可見(jiàn)性. 如果切入點(diǎn)要在多個(gè)切面中共用, 最好將它們集中在一個(gè)公共的類中. 在這種情況下, 它們必須被聲明為 public. 在引入這個(gè)切入點(diǎn)時(shí), 必須將類名也包括在內(nèi). 如果類沒(méi)有與這個(gè)切面放在同一個(gè)包中, 還必須包含包名.

其他通知可以通過(guò)方法名稱引入該切入點(diǎn).

十三绽榛、引入通知(只需了解即可)

引入通知是一種特殊的通知類型. 它通過(guò)為接口提供實(shí)現(xiàn)類, 允許對(duì)象動(dòng)態(tài)地實(shí)現(xiàn)接口, 就像對(duì)象已經(jīng)在運(yùn)行時(shí)擴(kuò)展了實(shí)現(xiàn)類一樣.

引入通知可以使用兩個(gè)實(shí)現(xiàn)類 MaxCalculatorImpl 和 MinCalculatorImpl, 讓 ArithmeticCalculatorImpl 動(dòng)態(tài)地實(shí)現(xiàn) MaxCalculator 和 MinCalculator 接口. 而這與從 MaxCalculatorImpl 和 MinCalculatorImpl 中實(shí)現(xiàn)多繼承的效果相同. 但卻不需要修改 ArithmeticCalculatorImpl 的源代碼

引入通知也必須在切面中聲明

在切面中, 通過(guò)為任意字段添加@DeclareParents 注解來(lái)引入聲明.

注解類型的 value 屬性表示哪些類是當(dāng)前引入通知的目標(biāo). value 屬性值也可以是一個(gè) AspectJ 類型的表達(dá)式, 以將一個(gè)即可引入到多個(gè)類中.? defaultImpl 屬性中指定這個(gè)接口使用的實(shí)現(xiàn)類

十四、用基于 XML 的配置聲明切面

除了使用 AspectJ 注解聲明切面, Spring 也支持在 Bean 配置文件中聲明切面. 這種聲明是通過(guò) aop schema 中的 XML 元素完成的.

正常情況下, 基于注解的聲明要優(yōu)先于基于 XML 的聲明. 通過(guò) AspectJ 注解, 切面可以與 AspectJ 兼容, 而基于 XML 的配置則是 Spring 專有的. 由于 AspectJ 得到越來(lái)越多的 AOP 框架支持, 所以以注解風(fēng)格編寫的切面將會(huì)有更多重用的機(jī)會(huì).

(1)聲明切面

當(dāng)使用 XML 聲明切面時(shí), 需要在根元素中導(dǎo)入 aop Schema

在 Bean 配置文件中, 所有的 Spring AOP 配置都必須定義在 <aop:config> 元素內(nèi)部. 對(duì)于每個(gè)切面而言, 都要?jiǎng)?chuàng)建一個(gè)<aop:aspect> 元素來(lái)為具體的切面實(shí)現(xiàn)引用后端 Bean 實(shí)例. 切面 Bean 必須有一個(gè)標(biāo)示符, 供 <aop:aspect> 元素引用

(2)聲明切入點(diǎn)

切入點(diǎn)使用 <aop:pointcut>元素聲明

切入點(diǎn)必須定義在<aop:aspect>元素下, 或者直接定義在 <aop:config> 元素下.

①婿屹、定義在<aop:aspect>元素下: 只對(duì)當(dāng)前切面有效

②灭美、定義在 <aop:config> 元素下: 對(duì)所有切面都有效

基于 XML 的 AOP 配置不允許在切入點(diǎn)表達(dá)式中用名稱引用其他切入點(diǎn).

(3)聲明通知

在 aop Schema 中, 每種通知類型都對(duì)應(yīng)一個(gè)特定的 XML 元素.

通知元素需要使用<pointcut-ref>來(lái)引用切入點(diǎn), 或用 <pointcut> 直接嵌入切入點(diǎn)表達(dá)式. method 屬性指定切面類中通知方法的名稱.

(4)聲明引入

可以利用 <aop:declare-parents> 元素在切面內(nèi)部聲明引入

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市昂利,隨后出現(xiàn)的幾起案子届腐,更是在濱河造成了極大的恐慌铁坎,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件犁苏,死亡現(xiàn)場(chǎng)離奇詭異硬萍,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)围详,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門朴乖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人助赞,你說(shuō)我怎么就攤上這事买羞。” “怎么了雹食?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵畜普,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我群叶,道長(zhǎng)吃挑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任街立,我火速辦了婚禮儒鹿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘几晤。我一直安慰自己约炎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布蟹瘾。 她就那樣靜靜地躺著圾浅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪憾朴。 梳的紋絲不亂的頭發(fā)上狸捕,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音众雷,去河邊找鬼灸拍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛砾省,可吹牛的內(nèi)容都是我干的鸡岗。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼编兄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼轩性!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起狠鸳,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤揣苏,失蹤者是張志新(化名)和其女友劉穎悯嗓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卸察,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脯厨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坑质。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片合武。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖洪乍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夜焦,我是刑警寧澤壳澳,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站茫经,受9級(jí)特大地震影響巷波,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卸伞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一抹镊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荤傲,春花似錦垮耳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至雾家,卻和暖如春铃彰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芯咧。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工牙捉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敬飒。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓邪铲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親无拗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子霜浴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 本章內(nèi)容: 面向切面編程的基本原理 通過(guò)POJO創(chuàng)建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,133評(píng)論 0 9
  • IoC 容器 Bean 的作用域 自定義作用域?qū)崿F(xiàn) org.springframework.beans.facto...
    Hsinwong閱讀 2,461評(píng)論 0 7
  • 一、AOP的基礎(chǔ) 1.1蓝纲、AOP是什么阴孟?晌纫?? 考慮這樣一個(gè)問(wèn)題:需要對(duì)系統(tǒng)中的某些業(yè)務(wù)做日志記錄永丝,比如支付系統(tǒng)中的...
    聶叼叼閱讀 2,108評(píng)論 2 17
  • 我锹漱,從小到大乖小孩沒(méi)干過(guò)出格的事,從小好好學(xué)習(xí)天天向上慕嚷,到高中也不只是為什么哥牍,比普通人努力點(diǎn),比學(xué)霸差點(diǎn)喝检,在班...
    冬歐尼閱讀 303評(píng)論 0 0
  • YCBanner輪播圖 主要引導(dǎo)界面滑動(dòng)導(dǎo)航 + 大于1頁(yè)時(shí)無(wú)限輪播 + 自定義指示器 項(xiàng)目地址:https://...
    楊充211閱讀 785評(píng)論 0 1