Spring AOP從入門(mén)到放棄之概念以及Spring Boot AOP demo

本文小福利 點(diǎn)我獲取阿里云優(yōu)惠券

AOP核心概念

1全蝶、橫切關(guān)注點(diǎn)

對(duì)哪些方法進(jìn)行攔截,攔截后怎么處理寺枉,這些關(guān)注點(diǎn)稱(chēng)之為橫切關(guān)注點(diǎn)

2抑淫、切面(aspect)-》(通知+切點(diǎn))

類(lèi)是對(duì)物體特征的抽象,切面就是對(duì)橫切關(guān)注點(diǎn)的抽象姥闪。
通知+切點(diǎn)
意思就是所有要被應(yīng)用到增強(qiáng)(advice)代碼的地方始苇。(包括方法的方位信息)

3、連接點(diǎn)(joinpoint)-》(被攔截的方法)

被攔截到的點(diǎn)筐喳,因?yàn)镾pring只支持方法類(lèi)型的連接點(diǎn)催式,所以在Spring中連接點(diǎn)指的就是被攔截的方法,實(shí)際上連接點(diǎn)還可以是字段或者構(gòu)造器

4避归、切入點(diǎn)(pointcut)-》(描述攔截那些方法的部分)

對(duì)連接點(diǎn)進(jìn)行攔截的定義

5荣月、通知(advice)-》(攔截后執(zhí)行自己業(yè)務(wù)邏輯的那些部分)

所謂通知指的就是指攔截到連接點(diǎn)之后要執(zhí)行的代碼,通知分為前置槐脏、后置喉童、異常、最終顿天、環(huán)繞通知五類(lèi)
這玩意也叫 增強(qiáng)
在邏輯層次上包括了我們抽取的公共邏輯和方位信息堂氯。因?yàn)镾pring只能方法級(jí)別的應(yīng)用AOP,也就是我們常見(jiàn)的before,after,after-returning,after-throwing,around五種,意思就是在方法調(diào)用前后牌废,異常時(shí)候執(zhí)行我這段公共邏輯唄咽白。

6、目標(biāo)對(duì)象

代理的目標(biāo)對(duì)象

7鸟缕、織入(weave)

將切面應(yīng)用到目標(biāo)對(duì)象并導(dǎo)致代理對(duì)象創(chuàng)建的過(guò)程晶框。
比如根據(jù)Advice中的方位信息在指定切點(diǎn)的方法前后排抬,執(zhí)行增強(qiáng)。這個(gè)過(guò)程Spring 替我們做好了授段。利用的是CGLIB動(dòng)態(tài)代理技術(shù)蹲蒲。

8、引入(introduction)

在不修改代碼的前提下侵贵,引入可以在運(yùn)行期為類(lèi)動(dòng)態(tài)地添加一些方法或字段

圖解

上面那一堆看不懂對(duì)嗎届搁? 我也不太懂。
來(lái)看張圖


這里寫(xiě)圖片描述

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

切面一共有五種通知

Before 某方法調(diào)用之前發(fā)出通知窍育。

前置通知(Before advice) :在某連接點(diǎn)(JoinPoint)之前執(zhí)行的通知卡睦, 但這個(gè)通知不能阻止連接點(diǎn)前的執(zhí)行。在方法調(diào)用之前發(fā)出通

    @Before("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void beforeTest() {
        System.out.println("執(zhí)行 方法 之前 調(diào)用----");
    }

After 某方法完成之后發(fā)出通知

后通知(After advice) :當(dāng)某連接點(diǎn)退出的時(shí)候執(zhí)行的通知(不論是正常 返回還是異常退出)漱抓。
不考慮方法運(yùn)行的結(jié)果 表锻。在方法調(diào)用之后發(fā)出通

    @After("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void afterTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 之后 調(diào)用----");
    }

After-returning 將通知放置在被通知的方法成功執(zhí)行之后。

方法正常返回后乞娄,調(diào)用通知瞬逊。在方法調(diào)用后,正常退出發(fā)出通

    @AfterReturning("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void afterReturningTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 AfterReturning 調(diào)用----");
    }

After-throwing 將通知放置在被通知的方法拋出異常之后补胚。

拋出異常后通知(After throwing advice) : 在方法拋出異常退出時(shí)執(zhí)行 的通知码耐。在方法調(diào)用時(shí)追迟,異常退出發(fā)出通

    @AfterThrowing("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void afterThrowingTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 AfterThrowing 調(diào)用----");
    }

Around 通知包裹在被通知的方法的周?chē)?/h2>

環(huán)繞通知(Around advice) :包圍一個(gè)連接點(diǎn)的通知溶其,類(lèi)似Web中Servlet 規(guī)范中的Filter的doFilter方法《丶洌可以在方法的調(diào)用前后完成自定義的行為瓶逃,也可以選擇不執(zhí)行。在方法調(diào)用之前和之后發(fā)出通

    @Around("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void aroundTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 前后 調(diào)用----");
    }

執(zhí)行結(jié)果

2017-10-27 19:51:51.605 DEBUG 15592 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/aspecttest] is: -1
執(zhí)行 方法 之前 調(diào)用----
JoinpointTest++++執(zhí)行我正常流水線(xiàn)的業(yè)務(wù)邏輯

執(zhí)行 方法 之后 調(diào)用----

執(zhí)行 方法 AfterReturning 調(diào)用----
2017-10-27 19:51:51.622 DEBUG 15592 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2017-10-27 19:51:51.622 DEBUG 15592 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet        : Successfully completed request

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

切入點(diǎn)指示符用來(lái)指示切入點(diǎn)表達(dá)式目的廓块,在Spring AOP中目前只有執(zhí)行方法這一個(gè)連接點(diǎn)厢绝,Spring AOP支持的AspectJ切入點(diǎn)指示符如下:

args()
定制join-point去匹配那些參數(shù)為指定類(lèi)型的方法的執(zhí)行動(dòng)作。

@args()
定制join-point去匹配那些參數(shù)被指定類(lèi)型注解的方法的執(zhí)行動(dòng)作

execution()
開(kāi)始匹配在其內(nèi)部編寫(xiě)的定制

this()
定制join-pont去匹配由AOP代理的Bean引用的指定類(lèi)型的類(lèi)带猴。

target()
定制join-point去匹配特定的對(duì)象昔汉,這些對(duì)象一定是指定類(lèi)型的類(lèi)。

@target()
定制join-point去匹配特定的對(duì)象拴清,這些對(duì)象要具有的指定類(lèi)型的注解靶病。

within()
定制join-point在必須哪一個(gè)包中。

@within()
定制join-point在必須由指定注解標(biāo)注的類(lèi)中口予。

@annotation
定制連接點(diǎn)具有指定的注解娄周。

只有execution用來(lái)執(zhí)行匹配,其他標(biāo)志符都只是為了限制/定制他們所要匹配的連接點(diǎn)的位置沪停。

命名及匿名切入點(diǎn)

這里寫(xiě)圖片描述

類(lèi)型匹配語(yǔ)法

*:匹配任何數(shù)量字符煤辨。

..:匹配任何數(shù)量字符的重復(fù)裳涛,如在類(lèi)型模式中匹配任何數(shù)量子包;而在方法參數(shù)模式中匹配任何數(shù)量參數(shù)众辨。

+:匹配指定類(lèi)型的子類(lèi)型端三;僅能作為后綴放在類(lèi)型模式后邊。

例子

java.lang.String    匹配String類(lèi)型鹃彻;
  
java.*.String       匹配java包下的任何“一級(jí)子包”下的String類(lèi)型技肩;
                    如匹配java.lang.String,但不匹配java.lang.ss.String  

java..*            匹配java包及任何子包下的任何類(lèi)型;  
                   如匹配java.lang.String浮声、java.lang.annotation.Annotation  
                  
java.lang.*ing     匹配任何java.lang包下的以ing結(jié)尾的類(lèi)型虚婿;  

java.lang.Number+  匹配java.lang包下的任何Number的自類(lèi)型;  
                   如匹配java.lang.Integer泳挥,也匹配java.math.BigInteger  

詳細(xì)語(yǔ)法

注解然痊? 修飾符? 返回值類(lèi)型 類(lèi)型聲明?方法名(參數(shù)列表) 異常列表?  

注解:可選屉符,方法上持有的注解剧浸,如@Deprecated;

修飾符:可選矗钟,如public唆香、protected;

返回值類(lèi)型:必填吨艇,可以是任何類(lèi)型模式躬它;“*”表示所有類(lèi)型;

類(lèi)型聲明:可選东涡,可以是任何類(lèi)型模式冯吓;

方法名:必填,可以使用“*”進(jìn)行模式匹配疮跑;

參數(shù)列表:“()”表示方法沒(méi)有任何參數(shù)组贺;“(..)”表示匹配接受任意個(gè)參數(shù)的方法,“(..,java.lang.String)”表示匹配接受java.lang.String類(lèi)型的參數(shù)結(jié)束祖娘,且其前邊可以接受有任意個(gè)參數(shù)的方法失尖;“(java.lang.String,..)” 表示匹配接受java.lang.String類(lèi)型的參數(shù)開(kāi)始,且其后邊可以接受任意個(gè)參數(shù)的方法渐苏;“(*,java.lang.String)” 表示匹配接受java.lang.String類(lèi)型的參數(shù)結(jié)束掀潮,且其前邊接受有一個(gè)任意類(lèi)型參數(shù)的方法;

異常列表:可選整以,以“throws 異常全限定名列表”聲明胧辽,異常全限定名列表如有多個(gè)以“,”分割公黑,如throws java.lang.IllegalArgumentException, java.lang.ArrayIndexOutOfBoundsException邑商。

匹配Bean名稱(chēng):可以使用Bean的id或name進(jìn)行匹配摄咆,并且可使用通配符“*”;

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

AspectJ使用 且(&&)人断、或(||)吭从、非(!)來(lái)組合切入點(diǎn)表達(dá)式恶迈。在Schema風(fēng)格下涩金,由于在XML中使用“&&”需要使用轉(zhuǎn)義字符“&&”來(lái)代替之,所以很不方便暇仲,因此Spring ASP 提供了and步做、or奈附、not來(lái)代替&&全度、||斥滤、!佑颇。

通知參數(shù)

使用JoinPoint獲榷サ簟:Spring AOP提供使用org.aspectj.lang.JoinPoint類(lèi)型獲取連接點(diǎn)數(shù)據(jù),任何通知方法的第一個(gè)參數(shù)都可以是JoinPoint(環(huán)繞通知是ProceedingJoinPoint挑胸,JoinPoint子類(lèi))痒筒,當(dāng)然第一個(gè)參數(shù)位置也可以是JoinPoint.StaticPart類(lèi)型嗜暴,這個(gè)只返回連接點(diǎn)的靜態(tài)部分。

這里寫(xiě)圖片描述

運(yùn)用場(chǎng)景

AOP 闷沥、IOC 做為Spring 的支柱,使用場(chǎng)景非常廣泛咐容。

1舆逃、日志記錄

我的另一篇博客

這里寫(xiě)圖片描述

2、權(quán)限控制

3戳粒、事務(wù)

4、多數(shù)據(jù)源讀寫(xiě)切換

我的另一篇博客

這里寫(xiě)圖片描述

原理

動(dòng)態(tài)代理
Spring中AOP代理由Spring的IOC容器負(fù)責(zé)生成奄妨、管理苹祟,其依賴(lài)關(guān)系也由IOC容器負(fù)責(zé)管理砸抛。因此,AOP代理可以直接使用容器中的其它bean實(shí)例作為目標(biāo)景东,這種關(guān)系可由IOC容器的依賴(lài)注入提供。Spring創(chuàng)建代理的規(guī)則為:

1奔誓、默認(rèn)使用Java動(dòng)態(tài)代理來(lái)創(chuàng)建AOP代理,這樣就可以為任何接口實(shí)例創(chuàng)建代理了

2和措、當(dāng)需要代理的類(lèi)不是代理接口的時(shí)候蜕煌,Spring會(huì)切換為使用CGLIB代理臼婆,也可強(qiáng)制使用CGLIB

spring boot 項(xiàng)目中定義使用自己的aop

1幌绍、引入jar

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

2、編寫(xiě)切面

@Aspect // FOR AOP
@Order(-99) // 控制多個(gè)Aspect的執(zhí)行順序傀广,越小越先執(zhí)行
@Component
public class AdviceTest {

@Pointcut(value="execution(* com.slife.java8.aspect.AspectTest.test())")
    public void poincut(){

    }

    @Before("poincut()")
    public void beforeTest() {
        System.out.println("執(zhí)行 方法 之前 調(diào)用----");
    }
}

這樣就完成了在spring boot 項(xiàng)目中定義使用自己的aop

注意代理模式

CGLIB動(dòng)態(tài)代理技術(shù)
有時(shí)候你會(huì)發(fā)現(xiàn) 你的配置和我一樣,但是aop沒(méi)有生效誓酒,這很有可能是SpringMVC的配置的代理模式不對(duì)贮聂。

問(wèn)題描述

方法里的xxxService對(duì)象如果使用autowared注入靠柑,無(wú)法啟動(dòng)aspect吓懈,
但是
xxxService = ctx.getBean("xxxxx")獲取,是可以啟用aspect的

原因

這個(gè)時(shí)候 xxxService 并不是注入進(jìn)來(lái)的耻警,即使有 @Autowired 注解隔嫡,這時(shí)的注解沒(méi)有任何作用。
只有 Spring 生成的對(duì)象才有 AOP 功能甘穿,因?yàn)?Spring 生成的代理對(duì)象才有 AOP 功能。

解決方法

配置spring.aop.proxy-target-class=true

不錯(cuò)的一個(gè)問(wèn)題描述已經(jīng)解決方法

文章代碼

/**
 * Created by chen on 2017/10/27.
 * <p>
 * Email 122741482@qq.com
 * <p>
 * Describe:
 */
@Service
public class JoinpointTest {

    public void JoinpointTest(){
        System.out.println("**********JoinpointTest*****************");
    }

    public void test(){
        System.out.println("JoinpointTest++++執(zhí)行我正常流水線(xiàn)的業(yè)務(wù)邏輯");
    }
}

@Aspect // FOR AOP
@Order(-99) // 控制多個(gè)Aspect的執(zhí)行順序秸滴,越小越先執(zhí)行
@Component
public class AdviceTest {

@Pointcut(value="execution(* com.slife.java8.aspect.AspectTest.test())")
    public void poincut(){

    }

    @Before("poincut()")
    public void beforeTest() {
        System.out.println("執(zhí)行 方法 之前 調(diào)用----");
    }

    @After("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void afterTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 之后 調(diào)用----");
    }

    @Around("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void aroundTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 前后 調(diào)用----");
    }



    @AfterReturning("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void afterReturningTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 AfterReturning 調(diào)用----");
    }



    @AfterThrowing("execution(* com.slife.java8.aspect.AspectTest.test())")
    public void afterThrowingTest() {
        System.out.println();
        System.out.println("執(zhí)行 方法 AfterThrowing 調(diào)用----");
    }


    @Before("execution(* com.slife.java8..*test*(..))")
    public void aspecttest1() {
        System.out.println();
        System.out.println("執(zhí)行 方法aspecttest1  Before 調(diào)用----");
    }


}

點(diǎn)擊獲取阿里云優(yōu)惠券

我的官網(wǎng)
[圖片上傳失敗...(image-8a5f4a-1509673150463)]

我的官網(wǎng)http://guan2ye.com
我的CSDN地址http://blog.csdn.net/chenjianandiyi
我的簡(jiǎn)書(shū)地址http://www.reibang.com/u/9b5d1921ce34
我的githubhttps://github.com/javanan
我的碼云地址https://gitee.com/jamen/
阿里云優(yōu)惠券https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=vf2b5zld&utm_source=vf2b5zld

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荡含,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子内颗,更是在濱河造成了極大的恐慌,老刑警劉巖均澳,帶你破解...
    沈念sama閱讀 212,222評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異糟袁,居然都是意外死亡躺盛,警方通過(guò)查閱死者的電腦和手機(jī)项戴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)周叮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人仿耽,你說(shuō)我怎么就攤上這事各薇∠詈兀” “怎么了峭判?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,720評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奕删。 經(jīng)常有香客問(wèn)我,道長(zhǎng)急侥,這世上最難降的妖魔是什么侮邀? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,568評(píng)論 1 284
  • 正文 為了忘掉前任贝润,我火速辦了婚禮,結(jié)果婚禮上打掘,老公的妹妹穿的比我還像新娘鹏秋。我一直安慰自己,他們只是感情好侣夷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布仑乌。 她就那樣靜靜地躺著,像睡著了一般晰甚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上厕九,一...
    開(kāi)封第一講書(shū)人閱讀 49,879評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音俊鱼,去河邊找鬼畅买。 笑死并闲,一個(gè)胖子當(dāng)著我的面吹牛皮获,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洒宝,決...
    沈念sama閱讀 39,028評(píng)論 3 409
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼宏浩!你這毒婦竟也來(lái)了靠瞎?” 一聲冷哼從身側(cè)響起比庄,我...
    開(kāi)封第一講書(shū)人閱讀 37,773評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤乏盐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后神凑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,220評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溉委,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坡慌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,697評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洪橘,死狀恐怖趴酣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岖寞,我是刑警寧澤,帶...
    沈念sama閱讀 34,360評(píng)論 4 332
  • 正文 年R本政府宣布仗谆,位于F島的核電站,受9級(jí)特大地震影響隶垮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜勉耀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評(píng)論 3 315
  • 文/蒙蒙 一蹋偏、第九天 我趴在偏房一處隱蔽的房頂上張望便斥。 院中可真熱鬧威始,春花似錦、人聲如沸黎棠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,782評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至户魏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叼丑,已是汗流浹背扛门。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,010評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留论寨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,433評(píng)論 2 360
  • 正文 我出身青樓葬凳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親劲装。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評(píng)論 2 350

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理占业,服務(wù)發(fā)現(xiàn)纯赎,斷路器,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • 基本知識(shí) 其實(shí), 接觸了這么久的 AOP, 我感覺(jué), AOP 給人難以理解的一個(gè)關(guān)鍵點(diǎn)是它的概念比較多, 而且坑爹...
    永順閱讀 8,146評(píng)論 5 114
  • 本博中關(guān)于spring的文章:Spring IOC和AOP原理念恍,Spring事務(wù)原理探究,Spring配置文件屬性...
    Maggie編程去閱讀 4,098評(píng)論 0 34
  • **** AOP 面向切面編程 底層原理 代理7寤铩R敉词爬! 今天AOP課程1权均、 Spring 傳統(tǒng) AOP2、 Spri...
    luweicheng24閱讀 1,359評(píng)論 0 1
  • 1叽赊、AOP concepts(AOP術(shù)語(yǔ)) Aspect/Advisors(切面)一個(gè)關(guān)注點(diǎn)的模塊化,這個(gè)關(guān)注點(diǎn)可...
    codersm閱讀 1,500評(píng)論 0 5