亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring AOP快速入門及開發(fā)步驟

 更新時間:2024年10月22日 14:48:03   作者:gobeyye  
Spring AOP(面向切面編程)核心概念包括切面(Aspect)、連接點(JoinPoint)、切點(Pointcut)、通知(Advice)等,通過在不改變原代碼的情況下,對方法進行增強,實現了代碼的解耦和功能擴展,本文帶來大家掌握Spring 中 AOP 的開發(fā)步驟,感興趣的朋友一起看看吧

Spring 框架有兩大核心 IoC,AOP。在前面我們已經學習過了 IoC 的相關知識,今天就讓我們開始 AOP 的學習。

一、AOP 概述

Aspect Oriented Programming(面向切面編程)。

切面就是指某一類特定問題,所以 AOP 也可以理解為面向特定方法編程。

**AOP 是一種思想,是對某一類事情的集中處理。**Spring AOP 是其中的一種實現方式。

AOP 的作用:在程序運行期間,在不修改源代碼的基礎上,對已有方法進行增強(無侵入性:解耦)。

二、Spring AOP 快速入門

我們先通過下面的程序體驗下 AOP 的開發(fā),并掌握 Spring 中 AOP 的開發(fā)步驟。

2.1 引入 AOP 依賴:

在 pom.xml 文件中添加配置:

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

2.2 編寫 AOP 程序:

@Aspect
@Slf4j
@Component
public class TestAspect {
    @Around("execution(* com.example.demo.controller.*.*(..))")
    public Object demo(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("方法執(zhí)行前執(zhí)行");
        Object result = joinPoint.proceed();
        log.info("方法執(zhí)行后執(zhí)行");
        return result;
    }
}

controller 類:

@RequestMapping("/test")
@RestController
@Slf4j
public class TestController {
    @RequestMapping("/t1")
    public void test1(){
        log.info("我是 test1");
    }
}

調用 controller 中的 test1 方法。

結果如下:

對程序進行簡單的講解:

  • @Aspect:標識這是一個切面類。
  • @Around:環(huán)繞通知,在目標方法的前后都會被執(zhí)行。后面的表達式表示對哪些方法進行增強。
  • ProceedingJoinPoint.proceed()讓原始方法執(zhí)行。

整個代碼劃分為三部分。

通過上面的程序,我們也可以感受到 AOP 面向切面編程的一些優(yōu)勢:

  • 代碼無侵入:不修改原始的業(yè)務方法,就可以對原始的業(yè)務方法進行了功能的增強或者是功能的改變。
  • 減少了重復代碼。
  • 提高開發(fā)效率。
  • 維護方便。

三、Spring AOP 詳解

3.1 Spring AOP 核心概念:

3.1.1 切點(Pointcut):

切點(Pointcut),也稱之為"切入點"。

Pointcut 的作用就是提供一組規(guī)則(使用 AspectJ pointcut expression language 來描述),告訴程序對哪些方法來進行功能增強。

上面的表達式 execution(* com.example.demo.controller..(…)) 就是切點表達式。

3.1.2 連接點(Join Point):

滿足切點表達式規(guī)則的方法,就是連接點。也就是可以被 AOP 控制的方法。

切點和連接點的關系:

連接點是滿足切點表達式的元素。切點可以看做是保存了眾多連接點的一個集合。

3.1.3 通知(Advice):

通知就是具體要做的工作,指哪些重復的邏輯,也就是共性功能(最終體現為一個方法)。

在 AOP 面向切面編程當中,我們把這部分重復的代碼邏輯抽取出來單獨定義,這部分代碼就是通知的內容。

3.1.4 切面(Aspect):

切面(Aspect)= 切點(Pointcut)+ 通知(Advice)。

通過切面就能夠描述當前 AOP 程序需要針對于哪些方法,在什么時候執(zhí)行什么樣的操作。

切面既包含了通知邏輯的定義,也包括了連接點的定義。

切面所在的類,我們一般稱為切面類(被 @Aspect 注解標識的類)。

3.2 通知類型:

上面我們講了什么是通知,接下來學習通知的類型。@Around 就是其中一種通知類型,表示環(huán)繞通知。Spring 中 AOP 的通知類型有以下幾種:

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

沒有異常的運行順序:

程序正常運行的情況下,@AfterThrowing 標識的通知方法不會執(zhí)行。

出現異常的運行順序:

@AfterReturning 標識的通知方法不會執(zhí)行,@AfterThrowing 標識的通知方法執(zhí)行了。

@Around 環(huán)繞通知中原始方法調用時有異常,通知中的環(huán)繞后的代碼邏輯也不會再執(zhí)行了(因為原始方法調用出異常了)。

注意:

  • @Around 環(huán)繞通知需要調用 ProceedingJoinPoint.proceed() 來讓原始方法執(zhí)行,其他通知不需要考慮目標方法執(zhí)行。
  • @Around 環(huán)繞通知方法的返回值,必須指定為 Object,來接收原始方法的返回值,否則原始方法執(zhí)行完畢,是獲取不到返回值的。
  • 一個切面類可以有多個切點。

3.3 @PointCut:

Spring 提供了 @PointCut 注解,把公共的切點表達式提取出來,需要用到時引用該切入點表達式即可,便于后續(xù)代碼的維護。

@Aspect
@Slf4j
@Component
public class TestAspect {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    public void pt(){}
    @Around("pt()")
    public Object demo(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("方法執(zhí)行前執(zhí)行");
        Object result = joinPoint.proceed();
        log.info("方法執(zhí)行后執(zhí)行");
        return result;
    }
}

當切點定義使用 private 修飾時,僅能在當前切面類中使用,當其他切面類也要使用當前切點定義時,就需要把 private 改為 public。引用方式為:全限定類名.方法名()。

@Slf4j
@Component
@Aspect
public class TestAspect2 {
    @Before("com.example.demo.aspect.TestAspect.pt()")
    public void doBefore() {
        log.info("執(zhí)? TestAspect2 -> Before ?法");
    }
}

3.4 切面優(yōu)先級 @Order:

當我們在一個項目中,定義了多個切面類時,并且這些切面類的多個切入點都匹配到了同一個目標方法。當目標方法運行的時候,這些切面類中的通知方法都會執(zhí)行,那么這幾個通知方法的執(zhí)行順序是什么樣的呢?

我們通過程序來進行驗證。

@Slf4j
@Component
@Aspect
public class TestAspect2 {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("執(zhí)行 TestAspect2 -> Before 方法");
    }
    //后置通知
    @After("pt()")
    public void doAfter() {
        log.info("執(zhí)行 TestAspect2 -> After 方法");
    }
}
@Aspect
@Component
@Slf4j
public class TestAspect3 {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("執(zhí)行 TestAspect3 -> Before 方法");
    }
    //后置通知
    @After("pt()")
    public void doAfter() {
        log.info("執(zhí)行 TestAspect3 -> After 方法");
    }
}
@Aspect
@Component
@Slf4j
public class TestAspect4 {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void doBefore() {
        log.info("執(zhí)行 TestAspect4 -> Before 方法");
    }
    //后置通知
    @After("pt()")
    public void doAfter() {
        log.info("執(zhí)行 TestAspect4 -> After 方法");
    }
}

運行上面程序:

通過上述程序的運行結果,可以看出:

存在多個切面類時,默認按照切面類的類名字母排序:

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

但這種方式不方便管理,我們的類名更多還是具備一定含義的。

Spring 給我們提供了一個新的注解,來控制這些切面通知的執(zhí)行順序:@Order。

@Slf4j
@Component
@Aspect
@Order(10)
public class TestAspect2 {
    //代碼省略
}
@Aspect
@Component
@Slf4j
@Order(5)
public class TestAspect3 {
    //代碼省略
}
@Aspect
@Component
@Slf4j
@Order(1)
public class TestAspect4 {
    //代碼省略
}

運行程序:

通過上述程序的運行結果,得出結論:

@Order 注解標識的切面類,執(zhí)行順序如下:

  • @Before 通知:數字越小先執(zhí)行。
  • @After 通知:數字越大先執(zhí)行。

@Order 的執(zhí)行順序可以抽象成下面這張圖:

3.5 切點表達式:

上面的代碼中,我們一直在使用切點表達式來描述切點。下面我們來介紹一下切點表達式的語法。

切點表達式常見有兩種表達方式:

  • execution:根據方法的簽名來匹配。
  • @annotation:根據注解匹配。

3.5.1 execution 表達式:

execution() 是最常用的切點表達式,用來匹配方法,語法為:

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

其中:訪問修飾符和異??梢允÷浴?/p>

切點表達式支持通配符表達:

  • * :匹配任意字符,只匹配一個元素(返回類型,包,類名,方法或者方法參數)。
  • 包名使用 * 表示任意包(一層包使用一個 * )。類名使用 * 表示任意類。返回值使用 * 表示任意返回值類型。
  • 方法名使用 * 表示任意方法(參數可能有限制)。
  • 參數使用 * 表示一個任意類型的參數。

..:匹配多個連續(xù)的任意符號,可以通配任意層級的包,或任意類型,任意個數的參數。

  • 使用..配置包名,標識此包以及此包下的所有子包。
  • 可以使用..配置參數,任意個任意類型的參數。

3.5.2 @annotation:

execution 表達式更適用有規(guī)則的,如果我們要匹配多個無規(guī)則的方法呢,比如:TestController 中的 t1() 和 UserController 中的 u1() 這兩個方法。這個時候我們使用 execution 這種切點表達式來描述就不是很方便了。我們可以借助自定義注解的方式以及另一種切點表達式 @annotation 來描述這一類的切點。

實現步驟:

  • 編寫自定義注解。
  • 使用 @annotation 表達式來描述切點。
  • 在方法上添加自定義注解。

創(chuàng)建一個注解類(和創(chuàng)建 Class 文件一樣的流程,選擇 Annotation 就可以了)

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

使用 @annotation 表達式來描述切點。

@Component
@Slf4j
@Aspect
public class MyAspectDemo {
    @Before("@annotation(com.example.demo.aspect.MyAspect)")
    public void doBefore(){
        log.info("我是 MyAspectDemo");
    }
}

在方法上添加自定義注解。

@RequestMapping("/test")
@RestController
@Slf4j
public class TestController {
    @MyAspect
    @RequestMapping("/t1")
    public void test1(){
        log.info("我是 test1");
    }
}

運行程序,訪問 test1 方法。

3.6 Spring AOP 的實現方式(常見面試題):

  • 基于注解 @Aspect。
  • 基于自定義注解(@annotation)。
  • 基于 Spring API(通過 xml 配置的方式,自從 SpringBoot 廣泛使用之后,這種方法幾乎看不到了)。
  • 基于代理來實現(更加久遠的一種實現方式,寫法笨重,不建議使用)。

四、代理模式

Spring AOP 是基于動態(tài)代理來實現 AOP 的。

代理模式,也叫委托模式。

定義:

為其他對象提供一種代理,以控制對這個對象的訪問。它的作用就是通過提供一個代理類,讓我們在調用目標方法的時候,不再是直接對目標方法進行調用,而是通過代理類間接調用。

代理模式可以在不修改被代理對象的基礎上,通過擴展代理類,進行一些功能的附加與增強。

根據代理的創(chuàng)建時期,代理模式分為靜態(tài)代理動態(tài)代理

  • 靜態(tài)代理:由程序員創(chuàng)建代理類或特定工具自動生成源代碼再對其編譯,在程序運行前代理類的 .class 文件就已經存在了。
  • 動態(tài)代理:在程序運行時,運用反射機制動態(tài)創(chuàng)建而成。

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

相關文章

  • Java替換int數組中重復數據的方法示例

    Java替換int數組中重復數據的方法示例

    這篇文章主要介紹了Java替換int數組中重復數據的方法,涉及java針對數組的遍歷、轉換、判斷等相關操作技巧,需要的朋友可以參考下
    2017-06-06
  • java判斷請求是來自PC端還是手機端小技巧

    java判斷請求是來自PC端還是手機端小技巧

    這篇文章主要為大家介紹了java判斷請求是來自PC端還是手機端小技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Java中的@PostConstruct注解的使用

    Java中的@PostConstruct注解的使用

    本文主要介紹了Java中的@PostConstruct注解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • java實現將文件上傳到ftp服務器的方法

    java實現將文件上傳到ftp服務器的方法

    這篇文章主要介紹了java實現將文件上傳到ftp服務器的方法,結合實例形式分析了基于java實現的ftp文件傳輸類定義與使用方法,需要的朋友可以參考下
    2016-08-08
  • Spring 多線程下注入bean問題詳解

    Spring 多線程下注入bean問題詳解

    本篇文章主要介紹了Spring 多線程下注入bean問題詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Springboot整合hibernate validator 全局異常處理步驟詳解

    Springboot整合hibernate validator 全局異常處理步驟詳解

    本文分步驟給大家介紹Springboot整合hibernate validator 全局異常處理,補呢文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-01-01
  • Java中Stream?API的使用示例詳解

    Java中Stream?API的使用示例詳解

    Java?在?Java?8?中提供了一個新的附加包,稱為?java.util.stream,該包由類、接口和枚舉組成,允許對元素進行函數式操作,?本文主要介紹了Java中Stream?API的具體使用,感興趣的小伙伴可以了解下
    2023-11-11
  • App登陸java后臺處理和用戶權限驗證

    App登陸java后臺處理和用戶權限驗證

    這篇文章主要為大家詳細介紹了App登陸java后臺處理和用戶權限驗證,感興趣的朋友可以參考一下
    2016-06-06
  • Idea中springboot項目的熱部署無法生效問題解決

    Idea中springboot項目的熱部署無法生效問題解決

    本文主要介紹了Idea中springboot項目的熱部署無法生效問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-10-10
  • Java 入門圖形用戶界面設計之列表框JList

    Java 入門圖形用戶界面設計之列表框JList

    圖形界面(簡稱GUI)是指采用圖形方式顯示的計算機操作用戶界面。與早期計算機使用的命令行界面相比,圖形界面對于用戶來說在視覺上更易于接受,本篇精講Java語言中關于圖形用戶界面的列表框JList
    2022-02-02

最新評論