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

Spring AOP原理解析

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

1.什么是Spring AOP?

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

Spring AOP就是為了解決這些問題存在,是AOP思想的其中一種實(shí)現(xiàn)方式

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

優(yōu)點(diǎn):

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

快速上手SpringAOP

編寫一個(gè)使用SpringAOP計(jì)算所有方法的運(yùn)行時(shí)長的例子

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

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

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

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í)行方法的路徑
    //參數(shù)部分的ProceedingJoinPoint joinPoint即要執(zhí)行的方法
    //不確定執(zhí)行方法的返回類型,因此在這里設(shè)返回類型為Object
    public Object timeRecord(ProceedingJoinPoint joinPoint) throws Throwable {
        long start=System.currentTimeMillis();//記錄方法執(zhí)行前時(shí)間
        //執(zhí)行方法
        Object proceed = joinPoint.proceed();//proceed()方法返回類型固定為Object
        long end=System.currentTimeMillis();//記錄方法執(zhí)行完的時(shí)間
        log.info(joinPoint.getSignature()+"方法耗時(shí):"+(end-start)+"ms");//getSignature()用于獲取執(zhí)行方法名
        return proceed;
    }
}

注解解釋:

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

Spring AOP 的核心術(shù)語

理解這些術(shù)語是掌握 AOP 的關(guān)鍵:

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

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

3.通知類型注解

寫兩個(gè)方法,用于測試

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 {
    //抽取切點(diǎn)
    @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 方法結(jié)束執(zhí)行");
        return result;
    }
}

結(jié)果展示:

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

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

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

4.@PointCut+@Order

@PointCut

在上面中存在大量的同樣的切點(diǎn)表達(dá)式,使用該注解能夠定義可重用的切點(diǎn)表達(dá)式,避免在多個(gè)通知中重復(fù)編寫相同的表達(dá)式。

通過@PointCut注解定義一個(gè)公共切點(diǎn)方法,該方法本身沒有實(shí)現(xiàn),僅作為切點(diǎn)表達(dá)式的載體:

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

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

定義好的切點(diǎn)可以在其他通知中通過方法名引用,避免重復(fù)編寫表達(dá)式:

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

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

@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 {
    //抽取切點(diǎn)
    @Pointcut("execution(* com.example.springaopdemo.controller.*.*(..))")
    public void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("執(zhí)行doBefore方法");
    }
}

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

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

@Order(3)

public class TestAspect(){}

@Order(2)

public class TestAspect2(){}

@Order(1)

public class TestAspect3(){}

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

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

有兩種

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

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

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

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

//自定義注解
@Retention(RetentionPolicy.RUNTIME)//設(shè)置生命周期
@Target({ElementType.METHOD})//設(shè)置注解使用位置
public @interface TimeRecord {
}
//注解通過切面實(shí)現(xiàn)
@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() + "耗時(shí)" + (end - start) + "ms");
        return result;
    }
}

注解完成自定義之后,只要在對(duì)應(yīng)方法添加該注解即可實(shí)現(xiàn)計(jì)算方法運(yùn)行時(shí)間的功能

6.代理模式

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

一個(gè)標(biāo)準(zhǔn)的代理模式通常包含三個(gè)角色:

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

分為靜態(tài)代理和動(dòng)態(tài)代理,區(qū)別在于代理對(duì)象的class文件生成的時(shí)機(jī)

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

動(dòng)態(tài)代理:程序運(yùn)行時(shí)動(dòng)態(tài)生成代理對(duì)象

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

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

7.Spring AOP原理

Spring AOP是通過動(dòng)態(tài)代理將橫切關(guān)注點(diǎn)(如日志,事務(wù))模塊化,并織入到目標(biāo)方法的編程范式

它的實(shí)現(xiàn)同時(shí)使用了jdk和CGlib

工作流程

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

此外ProxyFactory有個(gè)很重要的屬性proxyTargetClass,

SpringBoot默認(rèn)為true,Spring默認(rèn)為false

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

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

相關(guān)文章

  • Redis之SpringDataRedis用法詳解

    Redis之SpringDataRedis用法詳解

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

    Java的ConcurrentLinkedQueue源碼分析

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

    SpringBoot+redis配置及測試的方法

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

    Spring Boot整合Spring Security簡單實(shí)現(xiàn)登入登出從零搭建教程

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

    SpringSecurity的概念、認(rèn)證、授權(quán)機(jī)制剖析

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

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

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

    Java CGLib動(dòng)態(tài)代理機(jī)制(全面解析)

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

    SocketIo+SpringMvc實(shí)現(xiàn)文件的上傳下載功能

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

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

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

    Java實(shí)現(xiàn)獲取Excel中的表單控件

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

最新評(píng)論

苏尼特右旗| 望城县| 望谟县| 西城区| 永德县| 侯马市| 阳原县| 泸定县| 昌乐县| 花垣县| 萍乡市| 斗六市| 永寿县| 侯马市| 法库县| 新丰县| 咸阳市| 廊坊市| 奉新县| 舞阳县| 互助| 治县。| 元江| 瑞金市| 崇左市| 苗栗县| 高密市| 高碑店市| 泰兴市| 岳阳市| 英吉沙县| 徐汇区| 汤原县| 霍州市| 梓潼县| 英德市| 蒙自县| 瑞昌市| 汽车| 牟定县| 庆云县|