最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring AOP 的組成和實現(xiàn)

 更新時間:2023年07月31日 10:16:53   作者:小魚的學(xué)習(xí)筆記  
這篇文章主要介紹了Spring AOP 的組成和實現(xiàn),AOP 是一種思想,Spring AOP 是這種思想的具體實現(xiàn),本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下

1. Spring AOP 簡介

AOP 是一種思想,Spring AOP 是這種思想的具體實現(xiàn)。

OOP:面向?qū)ο缶幊?/p>

AOP:面向切面編程

AOP 面向切面編程,就是對某一類事情的集中處理。

比如,我們需要在 CSDN 上進行編輯博客、發(fā)布博客、刪除博客等操作,這些功能都是需要進行權(quán)限校驗的,判斷是否登錄

開發(fā)三階段

對于公共方法的處理:

  • (初級階段)每個方法都去實現(xiàn)
  • (中級階段)把同一類功能抽取成公共方法
  • (高級階段)采用 AOP 的方式,對代碼無侵入實現(xiàn)

除了統(tǒng)?的用戶登錄判斷之外,AOP 還可以實現(xiàn):

  • 統(tǒng)?日志記錄
  • 統(tǒng)一方法執(zhí)行時間統(tǒng)計
  • 統(tǒng)一的返回格式設(shè)置
  • 統(tǒng)一的異常處理
  • 事務(wù)的開啟和提交等
統(tǒng)一方法執(zhí)行時間統(tǒng)計項目監(jiān)控:監(jiān)控項目請求流量、監(jiān)控接口的響應(yīng)時間甚至每個方法的響應(yīng)時間
統(tǒng)一的返回格式設(shè)置

httpstatus: HTTP狀態(tài)碼

code: 業(yè)務(wù)狀態(tài)碼(后端響應(yīng)成功不代表業(yè)務(wù)辦理成功) 

msg: 業(yè)務(wù)處理失敗返回的信息

data: 

也就是說使用 AOP 可以擴充多個對象的某個能力,所以 AOP 可以說是 OOP(Object Oriented Programming,面向?qū)ο缶幊蹋┑?strong>補充和完善。

2. AOP 的組成

2.1 切面(Aspect)

切面(Aspect)由切點(Pointcut)和通知(Advice)組成,它既包含了橫切邏輯的定義,也包括了連接點的定義。

切面是包含了:通知、切點和切面的類,相當(dāng)于 AOP 實現(xiàn)的某個功能的集合。

2.2 連接點(Join Point)

應(yīng)?執(zhí)行過程中能夠插入切面的?個點,這個點可以是方法調(diào)用時、拋出異常時,甚至修改字段 時。切面代碼可以利用這些點插入到應(yīng)用的正常流程之中,并添加新的行為。

連接點相當(dāng)于需要被增強的某個 AOP 功能的所有方法。

2.3 切點(Pointcut)

Pointcut 是匹配 Join Point 的謂詞。 Pointcut 的作用就是提供?組規(guī)則(使用 AspectJ pointcut expression language 來描述)來匹配 Join Point,給滿足規(guī)則的 Join Point 添加 Advice。

切點相當(dāng)于保存了眾多連接點的一個集合(如果把切點看成一個表,而連接點就是表中?條?條 的數(shù)據(jù))。

2.4 通知(Advice)

切面也是有目標(biāo)的 ——它必須完成的工作。在 AOP 術(shù)語中,切面的工作被稱之為通知。

Spring 切面類中,可以在方法上使用以下注解,會設(shè)置方法為通知方法,在滿足條件后會通知本 方法進行調(diào)用:

  • 前置通知使用 @Before:通知方法會在目標(biāo)方法調(diào)用之前執(zhí)行。
  • 后置通知使用 @After:通知方法會在目標(biāo)方法返回或者拋出異常后調(diào)用。
  • 返回之后通知使用 @AfterReturning:通知方法會在目標(biāo)方法返回后調(diào)用。
  • 拋異常后通知使用 @AfterThrowing:通知方法會在目標(biāo)方法拋出異常后調(diào)用。
  • 環(huán)繞通知使用戶 @Around:通知包裹了被通知的方法,在被通知的方法通知之前和調(diào)用之后執(zhí)行自定義的行為。

切點相當(dāng)于要增強的方法。 

AOP 整個組成部分的概念如下圖所示,以多個頁面都要訪問用戶登錄權(quán)限為例:

既然說 AOP 是對一類事情的集中處理,那么我們就需要明確兩點:

  •  一類事情:處理對象的一個范圍
  •  集中處理:處理的內(nèi)容是什么

我們通過生活中的一個例子來看一下:

比如,我們乘坐高鐵需要安檢

那么,我們需要處理的內(nèi)容就是安檢;處理的范圍就是需要乘坐高鐵的人。

此處乘坐高鐵需要安檢這件事情就是切面,處理的內(nèi)容安檢就是通知,處理的范圍乘坐高鐵的人就是切點,具體有哪些人就是連接點。

切點是一個規(guī)則,事情的處理,最終作用在方法上。 

3. Spring AOP的實現(xiàn)

3.1 新建項目

3.2 添加 AOP 框架支持 

在 pom.xml 中添加如下配置:

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

3.3 定義切面、切點和通知

 我們先定義 UserController 類:

@RequestMapping("/user")
@RestController
public class UserController {
    // 獲取用戶信息
    @RequestMapping("/getInfo")
    public String getInfo(){
        return "get info...";
    }
    // 注冊
    @RequestMapping("/reg")
    public String reg(){
        return "reg...";
    }
    // Login
    @RequestMapping("/login")
    public String login(){
        return "login...";
    }
}

運行后,成功訪問: 

接下來,我們在 UserController 類中定義切面和切點: 

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {
    // 獲取用戶信息
    @RequestMapping("/getInfo")
    public String getInfo(){
        log.info("get info...");
        return "get info...";
    }
    // 注冊
    @RequestMapping("/reg")
    public String reg(){
        log.info("reg...");
        return "reg...";
    }
    // Login
    @RequestMapping("/login")
    public String login(){
        log.info("login...");
        return "login...";
    }
}

在 LoginAspect 類中使用 @Before 注解(通知方法會在目標(biāo)方法調(diào)用之前執(zhí)行): 

@Slf4j
@Component
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){}
    @Before("pointcut()")
    public void doBefore(){
        log.info("do berore...");
    }
}

我們接著新建一個 TestController 類:

@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {
    @RequestMapping("/hi")
    public String hi(){
        log.info("hi~");
        return "hi~";
    }
}

可以看到運行的結(jié)果中,并沒有在控制臺打印 @Before 中的內(nèi)容: 

那么為什么沒有執(zhí)行呢?

我們再來看一下其他注解,@After(通知方法會在目標(biāo)方法返回或者拋出異常后調(diào)用

@Slf4j
@Component
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){}
    @Before("pointcut()")
    public void doBefore(){
        log.info("do berore...");
    }
    @After("pointcut()")
    public void doAfter(){
        log.info("do after...");
    }
}

運行結(jié)果如下:

@AfterReturning(通知方法會在目標(biāo)方法返回后調(diào)用)

@Slf4j
@Component
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){}
    @Before("pointcut()")
    public void doBefore(){
        log.info("do berore...");
    }
    @After("pointcut()")
    public void doAfter(){
        log.info("do after...");
    }
    @AfterReturning("pointcut()")
    public void doAfterReturning(){
        log.info("do after returning...");
    }
}

運行以上代碼后: 

可以看到 :@AfterReturning 在 @After 之前被調(diào)用。

@AfterThrowing(通知方法會在目標(biāo)方法拋出異常后調(diào)用)

我們首先在 UserController 類中加入異常:

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {
    // 獲取用戶信息
    @RequestMapping("/getInfo")
    public String getInfo(){
        log.info("get info...");
        return "get info...";
    }
    // 注冊
    @RequestMapping("/reg")
    public String reg(){
        log.info("reg...");
        int a = 10/0;
        return "reg...";
    }
    // Login
    @RequestMapping("/login")
    public String login(){
        log.info("login...");
        return "login...";
    }
}

添加 @AfterThrowing 注解:

@Slf4j
@Component
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){}
    @Before("pointcut()")
    public void doBefore(){
        log.info("do berore...");
    }
    @After("pointcut()")
    public void doAfter(){
        log.info("do after...");
    }
    @AfterReturning("pointcut()")
    public void doAfterReturning(){
        log.info("do after returning...");
    }
    @AfterThrowing("pointcut()")
    public void doAfterThrowing(){
        log.info("do after throwing...");
    }
}

運行后可以看到: 

當(dāng)正常返回時,執(zhí)行 @AfterReturning 注解,當(dāng)出現(xiàn)異常時,不會執(zhí)行 @AfterReturning 注解;

當(dāng)出現(xiàn)異常時,才會執(zhí)行 @AfterThrowing 注解,當(dāng)正常返回時,不會執(zhí)行 @AfterThrowing 注解。

@Around(通知包裹了被通知的方法,在被通知的方法通知之前和調(diào)用之后執(zhí)行自定義的行為):

添加  @Around 注解:

@Slf4j
@Component
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){}
    @Before("pointcut()")
    public void doBefore(){
        log.info("do berore...");
    }
    @After("pointcut()")
    public void doAfter(){
        log.info("do after...");
    }
    @AfterReturning("pointcut()")
    public void doAfterReturning(){
        log.info("do after returning...");
    }
    @AfterThrowing("pointcut()")
    public void doAfterThrowing(){
        log.info("do after throwing...");
    }
    @Around("pointcut()")
    public void doAround(ProceedingJoinPoint joinPoint){
        log.info("環(huán)繞通知執(zhí)行之前...");
        try {
            joinPoint.proceed(); // 調(diào)用目標(biāo)方法
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        log.info("環(huán)繞通知執(zhí)行之后...");
    }
}

運行后界面顯示如下:

可以看到此時界面中不再有返回值,因此修改代碼如下:

@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint){
    Object oj = null;
    log.info("環(huán)繞通知執(zhí)行之前...");
    try {
        oj = joinPoint.proceed(); // 調(diào)用目標(biāo)方法
    } catch (Throwable e) {
        throw new RuntimeException(e);
    }
    log.info("環(huán)繞通知執(zhí)行之后...");
    return oj;
}

此時可以看到成功返回并打印了值: 

我們再來看一下這段代碼:

4. 切點表達式說明

AspectJ 支持三種通配符

  • * :匹配任意字符,只匹配一個元素(包,類,或方法,方法參數(shù))
  • .. :匹配任意字符,可以匹配多個元素 ,在表示類時,必須和 * 聯(lián)合使用。
  • + :表示按照類型匹配指定類的所有類,必須跟在類名后面,如 com.cad.Car+ ,表示繼承該類的 所有子類包括本身

切點表達式由切點函數(shù)組成,其中 execution() 是最常用的切點函數(shù),用來匹配方法,語法為: 

execution(<修飾符><返回類型><包.類.方法(參數(shù))><異常>)

5. 練習(xí):使用 AOP 統(tǒng)計 UserController 每個方法的執(zhí)行時間

@Slf4j
@Component
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){}
    @Before("pointcut()")
    public void doBefore(){
        log.info("do berore...");
    }
    @After("pointcut()")
    public void doAfter(){
        log.info("do after...");
    }
    @AfterReturning("pointcut()")
    public void doAfterReturning(){
        log.info("do after returning...");
    }
    @AfterThrowing("pointcut()")
    public void doAfterThrowing(){
        log.info("do after throwing...");
    }
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint){
        Object oj = null;
        log.info("環(huán)繞通知執(zhí)行之前...");
        try {
            oj = joinPoint.proceed(); // 調(diào)用目標(biāo)方法
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        log.info("環(huán)繞通知執(zhí)行之后...");
        return oj;
    }
    /**
     *
     * @param joinPoint 使用 AOP 統(tǒng)計 UserController 每個方法的執(zhí)行時間
     * @return
     */
    @Around("pointcut()")
    public Object doAroundCount(ProceedingJoinPoint joinPoint){
        Object oj = null;
        long start = System.currentTimeMillis();
        try {
            oj = joinPoint.proceed(); // 調(diào)用目標(biāo)方法
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        log.info(joinPoint.getSignature().toString()+"耗時:"+(System.currentTimeMillis()-start));
        return oj;
    }
}

可以看到不同的方法直接在 url 中進行更改重新運行界面即可獲得:

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

相關(guān)文章

  • Java中ArrayList刪除的常用操作及方法

    Java中ArrayList刪除的常用操作及方法

    ArrayList是最常用的一種java集合,在開發(fā)中我們常常需要從ArrayList中刪除特定元素,本文主要介紹了Java中ArrayList刪除的常用操作及方法,感興趣的可以了解一下
    2023-11-11
  • IntelliJ IDEA 配置與插件全部遷移到其他盤徹底釋放C盤空間

    IntelliJ IDEA 配置與插件全部遷移到其他盤徹底釋放C盤空間

    這篇文章給大家介紹IntelliJ IDEA 配置與插件全部遷移到其他盤徹底釋放C盤空間,本文將詳細解釋這一問題的根源,并提供兩種實用的遷移方案,幫你把 IDEA 的所有用戶數(shù)據(jù)安全地移到其他盤,徹底釋放 C 盤空間,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • SpringBoot解析JSON數(shù)據(jù)的三種方案

    SpringBoot解析JSON數(shù)據(jù)的三種方案

    JSON(JavaScript Object Notation) 是一種輕量級的數(shù)據(jù)交換格式,易于人閱讀和編寫,同時也易于機器解析和生成,本文給大家介紹了SpringBoot解析JSON數(shù)據(jù)的三種方案,需要的朋友可以參考下
    2024-03-03
  • Java對int[]數(shù)組做新增刪除去重操作代碼

    Java對int[]數(shù)組做新增刪除去重操作代碼

    這篇文章主要介紹了Java里面對int[]數(shù)組做新增刪除去重實現(xiàn),這里記錄下使用int[]數(shù)組對數(shù)組進行新增刪除去重等操作,用來更加了解java里面的集合類思想,需要的朋友可以參考下
    2023-10-10
  • Spring Boot 驗證碼框架 CAPTCHA詳解

    Spring Boot 驗證碼框架 CAPTCHA詳解

    這篇文章主要介紹了Spring Boot 驗證碼框架 CAPTCHA詳解,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Java 中的 CompletableFuture如何讓異步編程變得簡單

    Java 中的 CompletableFuture如何讓異步編程變得簡單

    CompletableFuture是Java 8引入的異步編程神器,它提供了強大的鏈式操作、任務(wù)組合和異常處理功能,使得異步編程變得簡單優(yōu)雅,本文給大家介紹Java中的CompletableFuture如何讓異步編程變得簡單,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • java枚舉enum和Enum類的使用

    java枚舉enum和Enum類的使用

    本文主要介紹了java枚舉enum和Enum類的使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Java web網(wǎng)站訪問量的統(tǒng)計

    Java web網(wǎng)站訪問量的統(tǒng)計

    這篇文章主要為大家詳細介紹了Java web網(wǎng)站訪問量的統(tǒng)計,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Java使用TCP套接字實現(xiàn)多人聊天功能詳解

    Java使用TCP套接字實現(xiàn)多人聊天功能詳解

    這篇文章主要介紹了Java使用TCP套接字實現(xiàn)多人聊天功能,結(jié)合實例形式詳細分析了java使用socket通信實現(xiàn)tcp協(xié)議下的聊天功能客戶端與服務(wù)器端相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2019-10-10
  • Java中的可重入鎖ReentrantLock簡析

    Java中的可重入鎖ReentrantLock簡析

    這篇文章主要介紹了Java中的可重入鎖ReentrantLock簡析,可重入是指同一個線程如果首次獲得了這把鎖,那么因為它是這把鎖的擁有者,因此有權(quán)利再次獲取這把鎖如果是不可重入鎖,那么第二次獲得鎖時,自己也會被鎖擋住,需要的朋友可以參考下
    2023-12-12

最新評論

固阳县| 会泽县| 丹凤县| 泰州市| 永安市| 广德县| 宣城市| 延边| 赤城县| 大埔区| 贵德县| 莱芜市| 兖州市| 新津县| 鄂托克旗| 璧山县| 孙吴县| 弥勒县| 克什克腾旗| 金堂县| 丰台区| 剑阁县| 讷河市| 简阳市| 娄烦县| 新建县| 万山特区| 含山县| 嘉禾县| 两当县| 日照市| 凤凰县| 炉霍县| 玉树县| 漾濞| 塔河县| 宁国市| 获嘉县| 青州市| 宁明县| 榆中县|