欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?AOP的注解實(shí)現(xiàn)方式實(shí)例詳解

 更新時(shí)間:2025年04月29日 10:02:26   作者:鴿鴿程序猿  
AOP是一種對(duì)某一類事情集中處理的思想,本文給大家介紹Spring?AOP的注解實(shí)現(xiàn)方式實(shí)例詳解,感興趣的朋友一起看看吧

一、AOP 與 Spring AOP

AOP:Aspect Oriented Programming(?向方?編程)。是一種對(duì)某一類事情集中處理的思想。

Spring AOP:就是對(duì)AOP思想的一種實(shí)現(xiàn)。

二、Spring AOP簡(jiǎn)單實(shí)現(xiàn)

我們簡(jiǎn)單實(shí)現(xiàn)一個(gè)統(tǒng)計(jì)每個(gè)接口的用時(shí)。

引入依賴:

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

寫AOP實(shí)現(xiàn):

  • 類使用注解@Aspect修飾
  • 方法參數(shù)為ProceedingJoinPoint 類,代表要實(shí)現(xiàn)的方法(只能在Around通知下寫)
  • 方法使用注解@Around,參數(shù)是對(duì)應(yīng)的路徑的切點(diǎn)
  • ProceedingJoinPoint 的參數(shù)執(zhí)行proceed方法。
package com.example.library.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class TimeAspect {
    @Around("execution(* com.example.library.controller.*.*(..) )")
    public Object recordTime(ProceedingJoinPoint  proceedingJoinPoint) throws Throwable {
        //開(kāi)始時(shí)間
        long start = System.currentTimeMillis();
        //執(zhí)行方法
        Object result = proceedingJoinPoint.proceed();
        //結(jié)束時(shí)間
        long end = System.currentTimeMillis();
        log.info("執(zhí)行時(shí)間:"+ (end-start) + "ms");
        return result;
    }
}

三、詳解Spring AOP

3.1 Spring AOP 核心概念

Spring AOP 核心概念:切點(diǎn),連接點(diǎn),通知,切面。

我們以上面的代碼來(lái)介紹。

3.1.1 切點(diǎn)(Pointcut)

切點(diǎn):就是告訴程序哪些方法需要使用到接下來(lái)的功能。
上面的@Around注解的參數(shù)就是切點(diǎn)表達(dá)式。

3.1.2 連接點(diǎn)(Join Point)

連接點(diǎn):滿?切點(diǎn)表達(dá)式規(guī)則的?法,就是連接點(diǎn)。也就是可以AOP控制的?法。

就像上面的代碼的連接點(diǎn)就是:com.example.library.controller路徑下的所有方法。

切點(diǎn)和連接點(diǎn)的關(guān)系:

  • 連接點(diǎn)是滿?切點(diǎn)表達(dá)式的元素。
  • 切點(diǎn)可以看做是保存了眾多連接點(diǎn)的?個(gè)集合。

3.1.3 通知(Advice)

通知:這個(gè)Spring AOP方法要實(shí)現(xiàn)的功能就是通知。

就像上面的實(shí)現(xiàn)一個(gè)統(tǒng)計(jì)每個(gè)接口的用時(shí)的需求,就是通知。

3.1.4 切面(Aspect)

切?(Aspect) = 切點(diǎn)(Pointcut) + 通知(Advice)。

通過(guò)切?就能夠描述當(dāng)前AOP程序需要針對(duì)于哪些?法,在什么時(shí)候執(zhí)?什么樣的操作。
切?既包含了通知邏輯的定義,也包括了連接點(diǎn)的定義。

3.2 通知類型

Spring中AOP的通知類型有以下?種:

  • @Around:環(huán)繞通知,此注解標(biāo)注的通知?法在?標(biāo)?法前,后都被執(zhí)?。
  • @Before:前置通知,此注解標(biāo)注的通知?法在?標(biāo)?法前被執(zhí)?。
  • @After:后置通知,此注解標(biāo)注的通知?法在?標(biāo)?法后被執(zhí)?,?論是否有異常都會(huì)執(zhí)?。
  • @AfterReturning:返回后通知,此注解標(biāo)注的通知?法在?標(biāo)?法后被執(zhí)?,有異常不會(huì)執(zhí)?。
  • @AfterThrowing:異常后通知,此注解標(biāo)注的通知?法發(fā)?異常后執(zhí)?。

效果:

package com.example.demoaop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Aspect
public class TestAspect {
    //前置通知
    @Before("execution(* com.example.demoaop.*.*(..) )")
    public void testBefore() {
        log.info("Before 方法執(zhí)行前");
    }
    //后置通知
    @After("execution(* com.example.demoaop.*.*(..) )")
    public void testAfter() {
        log.info("After 方法執(zhí)行后");
    }
    //返回后通知
    @AfterReturning("execution(* com.example.demoaop.*.*(..) )")
    public void testAfterReturning() {
        log.info("AfterReturning 返回后通知");
    }
    //拋出異常后通知
    @AfterThrowing("execution(* com.example.demoaop.*.*(..) )")
    public void testAfterThrowing() {
        log.info("AfterThrowing 拋出異常后通知");
    }
    //環(huán)繞通知
    @Around("execution(* com.example.demoaop.*.*(..) )")
    public void testAround(ProceedingJoinPoint pjp) throws Throwable {
        log.info("Around 方法執(zhí)行前");
        Object proceed = pjp.proceed();
        log.info("Around 方法執(zhí)行后");
    }
}

3.3 公共切點(diǎn)引用@PointCut

當(dāng)我們的切點(diǎn)表達(dá)式是一樣的時(shí)候,像上面我們還是在每一個(gè)通知類型的注解中,都使用了相同的表達(dá)式。
我們就可以使用方法注解@PointCut將切點(diǎn)表達(dá)式提取出來(lái),然后后面使用只需要寫方法名即可。
在其他切點(diǎn)類中也可以調(diào)用,需要將@PointCut注解所在類的路徑寫出來(lái)。

package com.example.demoaop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Aspect
public class TestAspect {
    @Pointcut("execution(* com.example.demoaop.*.*(..) )")
    public void pc(){}
    //前置通知
    @Before("pc()")
    public void testBefore() {
        log.info("TestAspect Before 方法執(zhí)行前");
    }
    //后置通知
    @After("pc()")
    public void testAfter() {
        log.info("TestAspect After 方法執(zhí)行后");
    }
}
package com.example.demoaop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Aspect
public class TestAspect2 {
    //前置通知
    @Before("com.example.demoaop.TestAspect.pc()")
    public void testBefore() {
        log.info("TestAspect2 Before 方法執(zhí)行前");
    }
    //后置通知
    @After("pc()")
    public void testAfter() {
        log.info("TestAspect2 After 方法執(zhí)行后");
    }
}

結(jié)果:
可以看見(jiàn)生效了,而且在其他切點(diǎn)類中只有加上了路徑的才生效了。

3.4 切點(diǎn)優(yōu)先級(jí)@Order

我們定義3個(gè)一樣的切點(diǎn)類,看他們的輸出順序:

存在多個(gè)切?類時(shí),默認(rèn)按照切?類的類名字?排序:

  • @Before 通知:字?排名靠前的先執(zhí)?
  • @After 通知:字?排名靠前的后執(zhí)?

但這種?式不?便管理,我們的類名更多還是具備?定含義的。
Spring 給我們提供了?個(gè)新的注解,來(lái)控制這些切?通知的執(zhí)?順序:@Order

我們將切點(diǎn)類的優(yōu)先級(jí)換一下:

@Component
@Slf4j
@Aspect
@Order(1)
public class TestAspect3 {
    //前置通知
    @Before("com.example.demoaop.TestAspect.pc()")
    public void testBefore() {
        log.info("TestAspect3 Before 方法執(zhí)行前");
    }
    //后置通知
    @After("com.example.demoaop.TestAspect.pc()")
    public void testAfter() {
        log.info("TestAspect3 After 方法執(zhí)行后");
    }
}
@Component
@Slf4j
@Aspect
@Order(2)
public class TestAspect2 {
    //前置通知
    @Before("com.example.demoaop.TestAspect.pc()")
    public void testBefore() {
        log.info("TestAspect2 Before 方法執(zhí)行前");
    }
    //后置通知
    @After("com.example.demoaop.TestAspect.pc()")
    public void testAfter() {
        log.info("TestAspect2 After 方法執(zhí)行后");
    }
}
@Component
@Slf4j
@Aspect
@Order(3)
public class TestAspect {
    @Pointcut("execution(* com.example.demoaop.*.*(..) )")
    public void pc(){}
    //前置通知
    @Before("pc()")
    public void testBefore() {
        log.info("TestAspect Before 方法執(zhí)行前");
    }
    //后置通知
    @After("pc()")
    public void testAfter() {
        log.info("TestAspect After 方法執(zhí)行后");
    }
}

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

規(guī)律:
@Order 注解標(biāo)識(shí)的切?類,執(zhí)?順序如下:

  • @Before 通知:數(shù)字越?先執(zhí)?
  • @After 通知:數(shù)字越?先執(zhí)?

像下圖的表示,箭頭代表執(zhí)行過(guò)程:

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

切點(diǎn)表達(dá)式用來(lái)描述切點(diǎn),常有以下兩種類型的切點(diǎn)表達(dá)式:execution 和 @annotation

3.5.1 execution

語(yǔ)法:

execution(<訪問(wèn)修飾限定符> <返回類型> <包名.類名.方法名(方法參數(shù))> <異常>)

含義:

  • 訪問(wèn)修飾限定符:表示切點(diǎn)對(duì)應(yīng)的方法的訪問(wèn)修飾限定符
  • 返回類型:表示切點(diǎn)對(duì)應(yīng)的方法的返回類型
  • 包名.類名.方法名(方法參數(shù)):表示切點(diǎn)對(duì)應(yīng)的方法的路徑及參數(shù)
  • 異常:表示切點(diǎn)對(duì)應(yīng)的方法拋出的異常
  • 訪問(wèn)修飾限定符 和 異常 可以省略

切點(diǎn)表達(dá)式?持通配符表達(dá):

:* 匹配任意字符,只匹配?個(gè)元素(返回類型,包,類名,?法或者?法參數(shù))
1.1. 包名使? * 表?任意包(?層包使??個(gè) * )
1.2. 類名使? * 表?任意類
1.3. 返回值使? * 表?任意返回值類型
1.4. ?法名使? * 表?任意?法
1.5. 參數(shù)使? * 表??個(gè)任意類型的參數(shù): 兩個(gè)點(diǎn) . . 匹配多個(gè)連續(xù)的任意符號(hào),可以通配任意層級(jí)的包,或任意類型,任意個(gè)數(shù)的參數(shù)
2.1. 使? . . 配置包名,標(biāo)識(shí)此包以及此包下的所有?包
2.2. 可以使? . . 配置參數(shù),任意個(gè)任意類型的參數(shù)

例子:

TestController 下的 public修飾,返回類型為String ?法名為t1的?參?法

execution(public String com.example.demo.TestController.t1())

匹配 TestController 下的所有?參?法

execution(* com.example.demo.TestController.*())

匹配controller包下所有的類的所有?法

execution(* com.example.demo.controller.*.*(..))

3.5.2 @annotation

當(dāng)我們要落實(shí)到不同類下個(gè)幾個(gè)方法,用上面的execution就有點(diǎn)捉襟見(jiàn)肘。
我們就可以使用?定義注解的?式以及另?種切點(diǎn)表達(dá)式 @annotation 來(lái)描述這?類的切點(diǎn)。

自定義注解:

在自定義類的時(shí)候選擇annotation:

然后就跟我們前面使用的注解一樣包含,生命周期@Retention,作用范圍@Target,交給Spring管理。

@Component
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAspect {
}

定義切面類:

  • 使用@Aspect注解修飾,
  • 交給Spring管理
  • 在通知類型的注解中使用:@annotation(自定義注解路徑) 作為參數(shù)。
@Slf4j
@Component
@Aspect
public class MyAspectDemo {
    @Around("@annotation( com.example.demoaop.MyAspect)")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        log.info("annotation 運(yùn)行前");
        pjp.proceed();
        log.info("annotation 運(yùn)行后");
    }
}

通過(guò)上面的方法,使用了自定義注解修飾的方法,就可以添加切面類的通知。

@RequestMapping("/test")
@RestController
@Slf4j
public class Test {
    @RequestMapping("/f1")
    public String f1() {
        log.info("f1");
        return "s1";
    }
    @MyAspect
    @RequestMapping("/f2")
    public Integer f2() {
        log.info("f2");
        return 1;
    }
    @RequestMapping("/f3")
    public Boolean f3() {
        log.info("f3");
        return false;
    }
}

訪問(wèn)f2 f1 f3 的結(jié)果:

除了上面講的基于注解的方式實(shí)現(xiàn)Spring AOP 還有遠(yuǎn)古的通過(guò)xml和代理的方式實(shí)現(xiàn)。參考Spring AOP其它實(shí)現(xiàn)方式

到此這篇關(guān)于Spring AOP的注解實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Spring AOP注解實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring5學(xué)習(xí)之基礎(chǔ)知識(shí)總結(jié)

    Spring5學(xué)習(xí)之基礎(chǔ)知識(shí)總結(jié)

    這篇文章主要介紹了Spring5學(xué)習(xí)之基礎(chǔ)知識(shí)總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • Java爬取豆瓣電影數(shù)據(jù)的方法詳解

    Java爬取豆瓣電影數(shù)據(jù)的方法詳解

    這篇文章主要介紹了Java爬取豆瓣電影數(shù)據(jù)的方法,結(jié)合實(shí)例形式詳細(xì)分析了Java爬取豆瓣電影數(shù)據(jù)相關(guān)原理、操作步驟、實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下
    2020-04-04
  • java設(shè)計(jì)模式-單例模式實(shí)現(xiàn)方法詳解

    java設(shè)計(jì)模式-單例模式實(shí)現(xiàn)方法詳解

    單例模式,屬于創(chuàng)建類型的一種常用的軟件設(shè)計(jì)模式。通過(guò)單例模式的方法創(chuàng)建的類在當(dāng)前進(jìn)程中只有一個(gè)實(shí)例(根據(jù)需要,也有可能一個(gè)線程中屬于單例
    2021-07-07
  • 如何修改maven默認(rèn)的JDK版本

    如何修改maven默認(rèn)的JDK版本

    這篇文章主要介紹了如何修改maven默認(rèn)的JDK版本,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Javaweb應(yīng)用使用限流處理大量的并發(fā)請(qǐng)求詳解

    Javaweb應(yīng)用使用限流處理大量的并發(fā)請(qǐng)求詳解

    這篇文章主要介紹了Javaweb應(yīng)用使用限流處理大量的并發(fā)請(qǐng)求詳解,還是挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-11-11
  • 淺談vue中子組件傳值的默認(rèn)值情況

    淺談vue中子組件傳值的默認(rèn)值情況

    這篇文章主要介紹了淺談vue中子組件傳值的默認(rèn)值情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • springmvc數(shù)據(jù)的封裝過(guò)程詳解

    springmvc數(shù)據(jù)的封裝過(guò)程詳解

    這篇文章主要介紹了springmvc數(shù)據(jù)的封裝過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Springboot2.x+Quartz分布式集群的實(shí)現(xiàn)

    Springboot2.x+Quartz分布式集群的實(shí)現(xiàn)

    這篇文章主要介紹了Springboot2.x+Quartz分布式集群的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • JavaWeb監(jiān)聽(tīng)器Listener實(shí)例解析

    JavaWeb監(jiān)聽(tīng)器Listener實(shí)例解析

    這篇文章主要為大家詳細(xì)介紹了JavaWeb監(jiān)聽(tīng)器Listener實(shí)例,針對(duì)監(jiān)聽(tīng)器進(jìn)行進(jìn)行細(xì)致分析,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Java中常見(jiàn)的陷阱題及答案

    Java中常見(jiàn)的陷阱題及答案

    在電腦里找到一份當(dāng)時(shí)學(xué)習(xí)JAVA時(shí)的筆記,看到一些現(xiàn)在已經(jīng)遺忘的細(xì)節(jié)。稍微整理了幾個(gè),發(fā)出來(lái)與大家分享。這篇文章主要介紹了Java中常見(jiàn)的陷阱題及答案,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-01-01

最新評(píng)論