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)稱之為橫切關(guān)注點(diǎn)

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

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

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

被攔截到的點(diǎn),因?yàn)镾pring只支持方法類型的連接點(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)繞通知五類
這玩意也叫 增強(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)行期為類動(dòng)態(tài)地添加一些方法或字段

圖解

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


這里寫(xiě)圖片描述

通知(Advice)類型

切面一共有五種通知

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 通知包裹在被通知的方法的周圍知。

環(huán)繞通知(Around advice) :包圍一個(gè)連接點(diǎn)的通知,類似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í)行我正常流水線的業(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ù)為指定類型的方法的執(zhí)行動(dòng)作。

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

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

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

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

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

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

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

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

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

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

這里寫(xiě)圖片描述

類型匹配語(yǔ)法

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

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

+:匹配指定類型的子類型;僅能作為后綴放在類型模式后邊。

例子

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

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

java.lang.Number+  匹配java.lang包下的任何Number的自類型;  
                   如匹配java.lang.Integer,也匹配java.math.BigInteger  

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

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

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

修飾符:可選,如public、protected;

返回值類型:必填,可以是任何類型模式;“*”表示所有類型;

類型聲明:可選,可以是任何類型模式;

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

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

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

匹配Bean名稱:可以使用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獲?。篠pring AOP提供使用org.aspectj.lang.JoinPoint類型獲取連接點(diǎn)數(shù)據(jù),任何通知方法的第一個(gè)參數(shù)都可以是JoinPoint(環(huán)繞通知是ProceedingJoinPoint,JoinPoint子類),當(dāng)然第一個(gè)參數(shù)位置也可以是JoinPoint.StaticPart類型,這個(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é)生成、管理,其依賴關(guān)系也由IOC容器負(fù)責(zé)管理。因此,AOP代理可以直接使用容器中的其它bean實(shí)例作為目標(biāo),這種關(guān)系可由IOC容器的依賴注入提供。Spring創(chuàng)建代理的規(guī)則為:

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

2、當(dāng)需要代理的類不是代理接口的時(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í)行我正常流水線的業(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.itdecent.cn/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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容