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

Spring AOP原理解析

 更新時間:2026年02月24日 15:04:44   作者:馬爾代夫哈哈哈  
AOP面向切片編程思想,是一種對一類問題集中處理的思想,Spring AOP就是為了解決這些問題存在,是AOP思想的其中一種實現方式,下面給大家詳細介紹Spring AOP原理解析,感興趣的朋友跟隨小編一起看看吧

1.什么是Spring AOP?

AOP=>面向切片編程思想,是一種對一類問題集中處理的思想,比如攔截器,統一返回結果管理,統一異常處理,登錄校驗......如果使用OOP(面向結果編程)會讓相同的代碼重復多次出現,業(yè)務方法中混雜著非核心的邏輯。

Spring AOP就是為了解決這些問題存在,是AOP思想的其中一種實現方式

2.SpringAOP優(yōu)點與上手

優(yōu)點:

  • 不影響原有代碼,解耦
  • 便于維護功能
  • 提高開發(fā)效率
  • 減少重復代碼

快速上手SpringAOP

編寫一個使用SpringAOP計算所有方法的運行時長的例子

1.在pom.xml文件引入依賴

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

注意:SpringBoot使用版本號為4.x.x, AOP依賴需要添加版本號

2.編寫AOP程序

package com.example.springbookdemo.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;
@Slf4j
@Aspect
@Component
public class TimeRecordAspect {
 @Around("execution(* com.example.springbookdemo.controller.*.*(..))")//該注解()中是要執(zhí)行方法的路徑
    //參數部分的ProceedingJoinPoint joinPoint即要執(zhí)行的方法
    //不確定執(zhí)行方法的返回類型,因此在這里設返回類型為Object
    public Object timeRecord(ProceedingJoinPoint joinPoint) throws Throwable {
        long start=System.currentTimeMillis();//記錄方法執(zhí)行前時間
        //執(zhí)行方法
        Object proceed = joinPoint.proceed();//proceed()方法返回類型固定為Object
        long end=System.currentTimeMillis();//記錄方法執(zhí)行完的時間
        log.info(joinPoint.getSignature()+"方法耗時:"+(end-start)+"ms");//getSignature()用于獲取執(zhí)行方法名
        return proceed;
    }
}

注解解釋:

  • Aspect=>標識切面類
  • Component=>將該類交給Spring容器管理,使其能自動掃描并注入
  • Around=>指明對哪些方法生效
  • Slf4j=>自動生成日志對象,可調用log.info()等方法打印日志

Spring AOP 的核心術語

理解這些術語是掌握 AOP 的關鍵:

  • Aspect(切面)
    • 是什么:橫切關注點的模塊化。它是一個,里面包含了需要被織入到業(yè)務代碼中的各種通知(Advice)。包含了切點,通知,連接點
  • Join Point(連接點)
    • 是什么:程序執(zhí)行過程中可以插入切面的點。在 Spring AOP 中,連接點總是代表執(zhí)行的方法。
  • Pointcut(切點)
    • 是什么:一個表達式,用于定義在哪些連接點上應用通知。它告訴 AOP:“在哪里” 執(zhí)行切面代碼。例如,你可以定義一個切點,匹配所有 com.example.service包下以 delete開頭的方法。
  • Advice(通知)
    • 是什么:切面在特定連接點上執(zhí)行的動作。指具體要做的?作, 指哪些重復的邏輯,它回答了 “什么時候” 和 “做什么” 的問題。
  • 類型
    • @Before:在目標方法執(zhí)行之前執(zhí)行。
    • @After:在目標方法執(zhí)行之后執(zhí)行(無論是否成功完成)。
    • @AfterReturning:在目標方法成功執(zhí)行并返回結果后執(zhí)行。
    • @AfterThrowing:在目標方法拋出異常后執(zhí)行。
    • @Around最強大的通知,它包圍了連接點??梢栽诜椒ㄕ{用前后執(zhí)行自定義行為,并決定是否繼續(xù)執(zhí)行方法、返回值或拋出異常。

用上面的例子來區(qū)分

3.通知類型注解

寫兩個方法,用于測試

package com.example.springaopdemo.controller;
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/t1")
    public String t1(){
        log.info("執(zhí)行t1");
        return "t1";
    }
    @RequestMapping("/t2")
    public boolean t2(){
        log.info("執(zhí)行t2");
        return true;
    }
}

編寫AOP

package com.example.springaopdemo.aspect;
@Aspect
@Component
@Slf4j
public class TestAspect {
    //抽取切點
    @Pointcut("execution(* com.example.springaopdemo.controller.*.*(..))")
    public void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("執(zhí)行doBefore方法");
    }
    //后置通知
    @After("pt()")
    public void doAfter() {
        log.info("執(zhí)行 After 方法");
    }
    //返回后通知
    @AfterReturning("pt()")
    public void doAfterReturning() {
        log.info("執(zhí)行 AfterReturning 方法");
    }
    //拋出異常后通知
    @AfterThrowing("pt()")
    public void doAfterThrowing() {
        log.info("執(zhí)行 doAfterThrowing 方法");
    }
    //添加環(huán)繞通知
    @Around("pt()")
    public Object doAround(ProceedingJoinPoint joinPoint)  {
        log.info("Around 方法開始執(zhí)行");
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        log.info("Around 方法結束執(zhí)行");
        return result;
    }
}

結果展示:

訪問t1=>即接口正常訪問

訪問t2=>即接口發(fā)生異常且不捕獲

訪問t2=>即接口發(fā)生異常且捕獲不throw

4.@PointCut+@Order

@PointCut

在上面中存在大量的同樣的切點表達式,使用該注解能夠定義可重用的切點表達式,避免在多個通知中重復編寫相同的表達式。

通過@PointCut注解定義一個公共切點方法,該方法本身沒有實現,僅作為切點表達式的載體:

@PointCut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}

重用切點表達式

定義好的切點可以在其他通知中通過方法名引用,避免重復編寫表達式:

@Before("serviceLayer()")
public void beforeService() {
    // 前置通知邏輯
}
@After("serviceLayer()")
public void afterService() {
    // 后置通知邏輯
}

@Order用于設置優(yōu)先級,控制多個切面的執(zhí)行順序,@Order(),()中的數字越小,優(yōu)先級越高

@Component
@Aspect
@Slf4j
public class TestAspect2 {
    @Before("com.example.springaopdemo.aspect.TestAspect.pt()")
    public void doBefore() {
        log.info("執(zhí)行doBefore2方法");
    }
}
@Component
@Aspect
@Slf4j
public class TestAspect3 {
    @Before("com.example.springaopdemo.aspect.TestAspect.pt()")
    public void doBefore() {
        log.info("執(zhí)行doBefore3方法");
    }
}
@Aspect
@Component
@Slf4j
public class TestAspect {
    //抽取切點
    @Pointcut("execution(* com.example.springaopdemo.controller.*.*(..))")
    public void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("執(zhí)行doBefore方法");
    }
}

執(zhí)行結果:也就是切面默認執(zhí)行順序(按照類名排序)

通過添加@Order注解可以人為控制切面執(zhí)行順序

@Order(3)

public class TestAspect(){}

@Order(2)

public class TestAspect2(){}

@Order(1)

public class TestAspect3(){}

添加之后執(zhí)行結果:

5.切點表達式

有兩種

第一種execution(<訪問修飾符><返回類型><包名.類名.方法名(方法參數)><異常>)

其中訪問修飾符和異??梢允÷?" * "匹配任意字符," .. "匹配多個連續(xù)符號

第二種@annotation=>自定義注解

相比較第一種有一定規(guī)律來說,想要執(zhí)行的方法沒有規(guī)律可以使用這種

//自定義注解
@Retention(RetentionPolicy.RUNTIME)//設置生命周期
@Target({ElementType.METHOD})//設置注解使用位置
public @interface TimeRecord {
}
//注解通過切面實現
@Aspect
@Component
@Slf4j
public class TimeRecordAspect {
    @Around("@annotation(com.example.springaopdemo.aspect.TimeRecord)")
    public  Object timeRecord(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        log.info(joinPoint.getSignature() + "耗時" + (end - start) + "ms");
        return result;
    }
}

注解完成自定義之后,只要在對應方法添加該注解即可實現計算方法運行時間的功能

6.代理模式

它為另一個對象提供一個替身或占位符,以控制對這個對象的訪問。其核心目的是:在不修改原始對象(目標對象)代碼的前提下,通過代理對象來增強或控制對目標對象的訪問。

一個標準的代理模式通常包含三個角色:

  • 抽象主題 (Subject): 定義了目標對象和代理對象的公共接口。這樣在任何使用目標對象的地方都可以透明地使用代理對象。
  • 真實主題 (Real Subject): 即“目標對象”,是業(yè)務邏輯的真正執(zhí)行者。
  • 代理 (Proxy): 持有對真實主題的引用,客戶端直接與代理交互。代理可以在調用真實主題的前后,添加額外的處理邏輯。

分為靜態(tài)代理和動態(tài)代理,區(qū)別在于代理對象的class文件生成的時機

靜態(tài)代理:程序運行之前就創(chuàng)建好了代理對象

動態(tài)代理:程序運行時動態(tài)生成代理對象

其中動態(tài)代理有兩種

  • jdk動態(tài)代理=>要求目標類必須實現至少一個接口。代理對象會實現與目標類相同的接口。
  • cGlib字節(jié)碼增強=>當目標類沒有實現接口時,Spring會使用CGLIB。它通過生成目標類的子類來創(chuàng)建代理,因此不能代理 final類或方法。

7.Spring AOP原理

Spring AOP是通過動態(tài)代理將橫切關注點(如日志,事務)模塊化,并織入到目標方法的編程范式

它的實現同時使用了jdk和CGlib

工作流程

  1. Spring容器啟動時,會自動掃描被@Aspect注解的類
  2. 通過掃描切點表達式,找到所有匹配的Bean(即目標對象)
  3. 通過ProxyFactory創(chuàng)建目標對象對應的代理對象(jdk/cglib)并將通知封裝成攔截器鏈
  4. 在調用代理對象方法時,攔截器鏈被觸發(fā),按順序執(zhí)行通知邏輯,最終調用目標方法

此外ProxyFactory有個很重要的屬性proxyTargetClass,

SpringBoot默認為true,Spring默認為false

可以通過在application.properties中進行配置:spring.aop.proxy-target-class=true/false

到此這篇關于Spring AOP原理解析的文章就介紹到這了,更多相關Spring AOP原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Redis之SpringDataRedis用法詳解

    Redis之SpringDataRedis用法詳解

    這篇文章主要介紹了Redis之SpringDataRedis的用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Java的ConcurrentLinkedQueue源碼分析

    Java的ConcurrentLinkedQueue源碼分析

    這篇文章主要介紹了Java的ConcurrentLinkedQueue源碼分析,ConcurrentLinkedQueue 是一個基于鏈接節(jié)點的無界線程安全的隊列,當我們添加一個元素的時候,它會添加到隊列的尾部,當我們獲取一個元素時,它會返回隊列頭部的元素,需要的朋友可以參考下
    2023-12-12
  • SpringBoot+redis配置及測試的方法

    SpringBoot+redis配置及測試的方法

    這篇文章主要介紹了SpringBoot+redis配置及測試的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • Spring Boot整合Spring Security簡單實現登入登出從零搭建教程

    Spring Boot整合Spring Security簡單實現登入登出從零搭建教程

    這篇文章主要給大家介紹了關于Spring Boot整合Spring Security簡單實現登入登出從零搭建的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧
    2018-09-09
  • SpringSecurity的概念、認證、授權機制剖析

    SpringSecurity的概念、認證、授權機制剖析

    Spring Security是一個強大且高度可定制的身份驗證和訪問控制框架,主要用于Java應用程序的安全性,這篇文章給大家介紹SpringSecurity的概念、認證、授權機制剖析,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • Java之while與do-while循環(huán)的用法詳解

    Java之while與do-while循環(huán)的用法詳解

    在上一篇文章中,給大家講解了循環(huán)的概念,并重點給大家講解了for循環(huán)的使用。但在Java中,除了for循環(huán)之外,還有while、do-while、foreach等循環(huán)形式。這篇文章給大家講解while循環(huán)的使用
    2023-05-05
  • Java CGLib動態(tài)代理機制(全面解析)

    Java CGLib動態(tài)代理機制(全面解析)

    下面小編就為大家?guī)硪黄狫ava CGLib動態(tài)代理機制(全面解析)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • SocketIo+SpringMvc實現文件的上傳下載功能

    SocketIo+SpringMvc實現文件的上傳下載功能

    這篇文章主要介紹了SocketIo+SpringMvc實現文件的上傳下載功能,socketIo不僅可以用來做聊天工具,也可以實現局域網。文中給出了實現代碼,需要的朋友可以參考下
    2018-08-08
  • java jdk1.8 使用stream流進行l(wèi)ist 分組歸類操作

    java jdk1.8 使用stream流進行l(wèi)ist 分組歸類操作

    這篇文章主要介紹了java jdk1.8 使用stream流進行l(wèi)ist 分組歸類操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Java實現獲取Excel中的表單控件

    Java實現獲取Excel中的表單控件

    Excel中可通過【開發(fā)工具】菜單欄下插入表單控件,如文本框、單選按鈕、復選框、組合框等等。本文將利用Java實現獲取Excel中的表單控件,需要的可以參考一下
    2022-05-05

最新評論

西丰县| 云和县| 微山县| 双桥区| 库伦旗| 栾城县| 霍城县| 两当县| 民丰县| 揭西县| 赣州市| 台南县| 淮北市| 宜君县| 齐河县| 昌平区| 沈阳市| 綦江县| 通海县| 阜新| 久治县| 石楼县| 淮北市| 温州市| 安仁县| 丘北县| 嘉黎县| 江津市| 西丰县| 玉林市| 招远市| 贵港市| 乾安县| 玛多县| 辽源市| 荥阳市| 辉南县| 莆田市| 维西| 南京市| 开远市|