Spring AOP詳解

AOP(Aspect Oriented Programming)镀梭,即面向切面編程屋确。
是OOP(Object Oriented Programming瘤睹,面向?qū)ο缶幊蹋┑难a(bǔ)充和完善。
AOP 要達(dá)到的效果是番电,在不修改源代碼的前提下岗屏,為業(yè)務(wù)組件添加某種通用功能。所以AOP 的本質(zhì)就是由 AOP 框架修改業(yè)務(wù)組件的源代碼漱办。
按照 修改源代碼的時(shí)機(jī),AOP 框架分為靜態(tài) AOP 實(shí)現(xiàn) 和動(dòng)態(tài) AOP 實(shí)現(xiàn)兩類(lèi)婉烟。

  • 靜態(tài) AOP 實(shí)現(xiàn)娩井, 通常使用AspectJ
  • 動(dòng)態(tài) AOP 實(shí)現(xiàn),通常使用 JDK 動(dòng)態(tài)代理似袁,或 CGlib 動(dòng)態(tài)代理
    Spring AOP是基于動(dòng)態(tài)代理實(shí)現(xiàn)的洞辣。Spring AOP會(huì)看看你的類(lèi)有沒(méi)有實(shí)現(xiàn)接口咐刨,有的話(huà)使用動(dòng)態(tài)代理,沒(méi)有的話(huà)使用cglib扬霜。

1 AspectJ

AOP 框架在編譯階段對(duì)程序目標(biāo)類(lèi)進(jìn)行修改定鸟,生成了靜態(tài)的 AOP 代理類(lèi)。使AOP 框架使用特定的編譯器著瓶,使生成的 *.class 文件被改掉了联予。
AOP相關(guān)的代碼,和目標(biāo)類(lèi)的結(jié)合過(guò)程叫做織入(weave)材原。AspectJ的織入過(guò)程沸久,有可能發(fā)生在三個(gè)階段:

  • 編譯時(shí)織入(Compile-time weaving)
    用AspectJ的編譯器ajc,在項(xiàng)目編譯的階段就將代碼織入目標(biāo)類(lèi)
  • 編譯后織入(Post-compile weaving)
    用AspectJ的編譯器ajc余蟹,向javac編譯出來(lái)的.class或者.jar織入代碼
  • 加載時(shí)織入(Load-time weaving)
    類(lèi)加載器將字節(jié)碼加載到JVM前織入

2 AOP核心概念

2.1 AOP相關(guān)術(shù)語(yǔ)

  • 連接點(diǎn)(Joinpoint)
    Joinpoint是程序在運(yùn)行過(guò)程中能夠插入Aspect的地點(diǎn)卷胯,比如方法調(diào)用、異常拋出威酒、字段修改等窑睁。 在 Spring AOP 中,連接點(diǎn)總是方法的調(diào)用葵孤。

  • 切入點(diǎn)(Pointcut)
    Pointcut用于定義Advice應(yīng)該切入到哪些Joinpoint上卵慰, 根據(jù)Pointcut的通配或者正則表達(dá)式來(lái)定義要攔截的Joinpoint

  • 通知(Advice)
    Advice定義了在Pointcut上執(zhí)行的增強(qiáng)處理佛呻,是攔截到Joinpoint之后要執(zhí)行的代碼裳朋。

  • 切面(Aspect)
    Aspect通常是一個(gè)類(lèi),可以定義PointcutAdvice吓著。Aspect指明在哪個(gè)Pointcut執(zhí)行什么Advice鲤嫡。

  • 目標(biāo)對(duì)象(Target)
    目標(biāo)對(duì)象是指代理的目標(biāo)對(duì)象,是指要織入Advice的對(duì)象绑莺。

  • 織入(weaving)
    通過(guò)Pointcut切入伟姐,將Aspect應(yīng)用到Target并創(chuàng)建代理對(duì)象創(chuàng)建

  • 引入(Introduction)
    在不修改目標(biāo)對(duì)象的前提下,引入可以在運(yùn)行期為類(lèi)動(dòng)態(tài)地添加一些方法或字段

image.png

2.2 通知Advice 的類(lèi)型

Advice可以分為前置通知Before慨丐、后置通知AfterReturning菩貌、異常通知AfterThrowing、最終通知After欺缘、環(huán)繞通知Around五類(lèi)栋豫。

  • 前置通知 before
    在Joinpoint前被執(zhí)行的Advice
  • 后置通知 AfterReturning
    在一個(gè)Joinpoint 正常返回后執(zhí)行的Advice
  • 異常通知 AfterThrowing
    當(dāng)一個(gè)Joinpoint 拋出異常后執(zhí)行的Advice
  • 最終通知 after
    Joinpoint 無(wú)論是正常退出還是發(fā)生了異常,都會(huì)被執(zhí)行的 advice.
  • 環(huán)繞通知 around
    在Joinpoint前和Joinpoint退出后都執(zhí)行的Advice谚殊。 這個(gè)是最常用的 Advice.
  • introduction
    introduction可以為原有的對(duì)象增加新的屬性和方法
image.png

各個(gè)通知的執(zhí)行順序如圖所示丧鸯。

3 Spring AOP的代碼demo

Spring借用了@AspectJ的注解來(lái)定義切面。在Spring Boot中引入AOP Starter依賴(lài):

     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
     </dependency>

AopAutoConfiguration會(huì)添加@EnableAspectJAutoProxy注解以開(kāi)啟AspectJ注解的使用嫩絮,也就是說(shuō)加了@Aspect注解的切面類(lèi)丛肢,一放到容器中围肥,Spring AOP就自動(dòng)完成織入。

3.1 定義注解MyLogger
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLogger {

}
3.2 定義Pointcut
   /**
     * 定義切點(diǎn)蜂怎,匹配所有使用了@MyLogger注解的方法
     */
    @Pointcut("@annotation( com.dc.artemis.server.qian.MyLogger)")
    public void logPointcut() {
    }
3.3 定義Advice
 /**
     * 這里使用環(huán)繞通知
     */
   @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("@Around before");
        Object returnValue = joinPoint.proceed();
        log.info("@Around after");
        return returnValue;
    }
3.4 切面Aspect完整的代碼
@Slf4j
@Aspect // 使用注解定義切面
@Component
@EnableAspectJAutoProxy // 開(kāi)啟AOP
public class LogAspect {
    
    /**
     * 定義切點(diǎn)穆刻,匹配所有使用了@MyLogger注解的方法
     */
    @Pointcut("@annotation( com.dc.artemis.server.qian.MyLogger)")
    public void logPointcut() {
    }


    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("@Around before");

        Object returnValue = joinPoint.proceed();
        log.info("@Around after");
        return returnValue;
    }
}
3.5 測(cè)試

調(diào)用

  @Test
    void testMyService() {
        myService.myMethod();
    }

輸出

2022-10-15 17:34:04.470  INFO 87770 --- [main] com.dc.artemis.server.qian.LogAspect : @Around before
2022-10-15 17:34:04.496  INFO 87770 --- [main] com.dc.artemis.server.qian.MyService: 執(zhí)行方法
2022-10-15 17:34:04.497  INFO 87770 --- [main] com.dc.artemis.server.qian.LogAspect: @Around after

由于MyService沒(méi)有實(shí)現(xiàn)接口,可以看到Spring使用了CGLIB生成代理對(duì)象

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末杠步,一起剝皮案震驚了整個(gè)濱河市氢伟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌篮愉,老刑警劉巖腐芍,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異试躏,居然都是意外死亡猪勇,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)颠蕴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)泣刹,“玉大人,你說(shuō)我怎么就攤上這事犀被∫文” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵寡键,是天一觀的道長(zhǎng)掀泳。 經(jīng)常有香客問(wèn)我,道長(zhǎng)西轩,這世上最難降的妖魔是什么员舵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮藕畔,結(jié)果婚禮上马僻,老公的妹妹穿的比我還像新娘。我一直安慰自己注服,他們只是感情好韭邓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著溶弟,像睡著了一般女淑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上可很,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天诗力,我揣著相機(jī)與錄音,去河邊找鬼我抠。 笑死苇本,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的菜拓。 我是一名探鬼主播瓣窄,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼纳鼎!你這毒婦竟也來(lái)了俺夕?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贱鄙,失蹤者是張志新(化名)和其女友劉穎劝贸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逗宁,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡映九,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瞎颗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片件甥。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖哼拔,靈堂內(nèi)的尸體忽然破棺而出引有,到底是詐尸還是另有隱情,我是刑警寧澤倦逐,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布譬正,位于F島的核電站,受9級(jí)特大地震影響檬姥,放射性物質(zhì)發(fā)生泄漏曾我。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一穿铆、第九天 我趴在偏房一處隱蔽的房頂上張望您单。 院中可真熱鬧,春花似錦荞雏、人聲如沸虐秦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悦陋。三九已至,卻和暖如春筑辨,著一層夾襖步出監(jiān)牢的瞬間俺驶,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工棍辕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留暮现,地道東北人还绘。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像栖袋,于是被迫代替她去往敵國(guó)和親拍顷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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