【SSM框架】Spring筆記 --- AOP詳解;AspectJ中四種通知的使用

来源:https://www.cnblogs.com/Burning-youth/archive/2022/05/25/16310931.html
-Advertisement-
Play Games

切麵:公共的,通用的,重覆的功能稱為切麵,面向切麵編程就是將切麵提取出來,單獨開發,在需要調用的方法中通過動態代理的方式進行織入 ...


1、面向切麵編程AOP


AOP(Aspect Orient Programming),面向切麵編程。

切麵:公共的,通用的,重覆的功能稱為切麵,面向切麵編程就是將切麵提取出來,單獨開發,在需要調用的方法中通過動態代理的方式進行織入。

 

2、AOP框架的"進化"


1)第一個版本:業務和切麵緊耦合在一起,沒有拆分.

2)第二個版本:使用子類代理的方式拆分業務和切麵.

3)第三個版本:使用靜態代理拆分業務和切麵.業務和業務介面已拆分.此時切麵緊耦合在業務中

4)第四個版本:使用靜態代理拆分業務和業務介面,切麵和切麵介面.

5)第五個版本:使用動態代理完成第四個版本的優化.

 

3、Spring支持的AOP的實現


Spring支持AOP的編程,常用的有以下幾種:

1)Before通知:在目標方法被調用前調用,涉及介面為 org.springframework.aop.MethodBeforeAdvice

2)After通知:在目標方法被調用後調用,涉及介面為 org.springframework.aop.AfterReturningAdvice

3)Throws通知:在目標方法拋出異常時調用,涉及介面為 org.springframework.aop.ThrowsAdvice

4)Around通知:攔截對目標對象方法調用,涉及介面為 org.aopalliance.intercept.MethodInterceptor

 

4、AOP常用的術語


1)切麵:就是那些重覆的,公共的,通用的功能稱為切麵,例如:日誌,事務,許可權.

2)連接點:就是目標方法.因為在目標方法中要實現目標方法的功能和切麵功能.

3)切入點(Pointcut):指定切入的位置,多個連接點構成切入點,切入點可以是一個目標方法,可以是一個類中的所有方法,可以是某個包下的所有類中的方法.

4)目標對象:操作誰,誰就是目標對象.

5)通知(Advice):來指定切入的時機,是在目標方法執行前還是執行後還是出錯時,還是環繞目標方法切入切麵功能.
  

5、AspectJ框架


  • AspectJ 是一個優秀的面向切麵的框架,它擴展了 Java 語言,提供了強大的切麵實現。它因為是基於java語言開發的,所以無縫擴展

 

AspectJ 中常用的通知有四種類型:

1)前置通知@Before

2)後置通知@AfterReturning

3)環繞通知@Around

4)最終通知@After

5)定義切入點@Pointcut(瞭解)

 

6、AspectJ 的切入點表達式(掌握)


規範的公式:

  • execution(訪問許可權 方法返回值 方法聲明(參數) 異常類型)

可簡化為:

  • execution( 方法返回值 方法聲明(參數) )

用到的符號:

    *   代表任意(通配符)
    ..   如果出現在方法的參數中,則代表任意參數;如果出現在路徑中,則代表本路徑及其所有的子路徑(其實就相當於路徑中的省略號唄)

 

示例:

//任意的公共方法:

execution(public * *(..)) 

//任何一個以“set”開始的方法

execution(* set*(..))

//任意的返回值類型,在com.xyz.service.impl包下的任意類的任意方法

execution(* com.xyz.service.impl.*.*(..))

//任意的返回值類型 ,在com.xyz.service及其子包下的任意類的任意方法

execution(* com.xyz.service..*.*(..))

//service之前可以有任意的子包

execution(* *..service.*.*(..))

//service之前只有一個包

execution(* *.service.*.*(..))

 

7、AspectJ的前置通知@Before:


  • 在目標方法執行前切入切麵功能,在切麵方法中不可以獲得目標方法的返回值,只能得到目標方法的簽名。

實現的步驟:

1)添加依賴:
   

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.5.RELEASE</version> 
</dependency>


2)創建業務介面

3)創建業務實現

4)創建切麵類,實現切麵方法

5)在applicationContext.xml文件中進行切麵綁定

 

慄子:  

@Aspect  //交給AspectJ的框架去識別切麵類
@Component
public class MyAspect {
    /**
     * 所有切麵的功能都是由切麵方法來實現的
     * 可以將各種切麵都在此類中進行開發
     *
     * 前置通知的切麵方法的規範
     * 1)訪問許可權是public
     * 2)方法的返回值是void
     * 3)方法名稱自定義
     * 4)方法沒有參數,如果有也只能是JoinPoint類型
     * 5)必須使用@Before註解來聲明切入的時機是前切功能和切入點
     *   參數:value  指定切入點表達式
     *
     * 業務方法
     * public String doSome(String name, int age)
     */
    @Before(value = "execution(public String com.bjpowernode.s01.SomeServiceImpl.*(String,int))")
    public void myBefore(){
        System.out.println("切麵方法中的前置通知功能實現............");
    }

    @Before(value = "execution(public * com.bjpowernode.s01.SomeServiceImpl.*(..))")
    public void myBefore(){
        System.out.println("切麵方法中的前置通知功能實現............");
    }

    @Before(value = "execution( * com.bjpowernode.s01.*.*(..))")
    public void myBefore(JoinPoint jp){
        System.out.println("切麵方法中的前置通知功能實現............");
        System.out.println("目標方法的簽名:"+jp.getSignature());
        System.out.println("目標方法的參數:"+ Arrays.toString(jp.getArgs()));
    }
    @Before(value = "execution( * com.bjpowernode.s01..*(..))")
    public void myBefore(){
        System.out.println("切麵方法中的前置通知功能實現............");
    }

    @Before(value = "execution( * *(..))")
    public void myBefore(){
        System.out.println("切麵方法中的前置通知功能實現............");
    }
}

 

AspectJ框架切換JDK動態代理和CGLib動態代理:

<!--預設是JDK動態代理,取時必須使用介面類型-->
<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>  
<!--設置為CGLib子類代理,可以使用介面和實現類接,記住:使用介面來接,永遠不出錯-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>  

 

8、@AfterReturning後置通知:


  • 後置通知是在目標方法執行後切入切麵功能,可以得到目標方法的返回值.如果目標方法的返回值是簡單類型(8種基本類型+String)則不可改變.如果目標方法的返回值是引用類型則可以改變.
        
@Aspect
@Component
public class MyAspect {
    /**
   * 後置通知的方法的規範
   * 1)訪問許可權是public
   * 2)方法沒有返回值void
   * 3)方法名稱自定義
   * 4)方法有參數(也可以沒有參數,如果目標方法沒有返回值,則可以寫無參的方法,但一般會寫有參,這樣可以處理無參可以處理有參),這個切麵方法的參數就是目標方法的返回值
   * 5)使用@AfterReturning註解表明是後置通知
   *   參數:
   *      value:指定切入點表達式
   *      returning:指定目標方法的返回值的名稱,則名稱必須與切麵方法的參數名稱一致.
   */
    @AfterReturning(value = "execution(* com.bjpowernode.s02.*.*(..))",returning = "obj")
    public void myAfterReturning(Object obj){
        System.out.println("後置通知功能實現..............");
        if(obj != null){
            if(obj instanceof String){
                obj = obj.toString().toUpperCase();
                System.out.println("在切麵方法中目標方法的返回值:"+obj);
            }
            if(obj instanceof Student){
                Student stu = (Student) obj;
                stu.setName("李四");
                System.out.println("在切麵方法中目標方法的返回值:"+stu);
            }
        }
    }
}

 

9、環繞通知@Around:


  • 它是通過攔截目標方法的方式 ,在目標方法前後增強功能的通知,它是功能最強大的通知,一般事務使用此通知.它可以輕易的改變目標方法的返回值.

 

@Aspect
@Component
public class MyAspect {
    /**
     * 環繞通知方法的規範
     * 1)訪問許可權是public
     * 2)切麵方法有返回值,此返回值就是目標方法的返回值
     * 3)方法名稱自定義
     * 4)方法有參數,此參數就是目標方法
     * 5)迴避異常Throwable
     * 6)使用@Around註解聲明是環繞通知
     *   參數:
     *      value:指定切入點表達式
     */

    @Around(value = "execution(* com.bjpowernode.s03.*.*(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        //前切功能實現
        System.out.println("環繞通知中的前置功能實現............");
        //目標方法調用
        Object obj = pjp.proceed(pjp.getArgs());
        //後切功能實現
        System.out.println("環繞通知中的後置功能實現............");
        return obj.toString().toUpperCase();  //改變了目標方法的返回值
    }
}

 

10、最終通知@After


無論目標方法是否正常執行,最終通知的代碼都會被執行.

 

@Aspect
@Component
public class MyAspect {
    /**
     * 最終方法的規範
     * 1)訪問許可權是public
     * 2)切麵方法沒有返回值void
     * 3)方法名稱自定義
     * 4)方法可以沒有參數,也可以有,則JoinPoint.
     * 5)使用@After註解
     * 6)參數:value:指定切入點表達式
     */
    @After(value = "execution(* com.bjpowernode.s04.SomeServiceImpl.*(..))")
    public void myAfter(){
        System.out.println("最終通知被執行.............");
    }
}

 

11、給切入點表達式起別名@Pointcut


如果多個切麵切入到同一個切入點,可以使用別名簡化開發。使用@Pointcut註解,創建一個空方法,此方法的名稱就是別名。
   

@Aspect
@Component
public class MyAspect {
    /**
   * 最終通知方法的規範
   * 1)訪問許可權是public
   * 2)方法沒有返回值
   * 3)方法名稱自定義
   * 4)方法沒有參數,如果有也只能是JoinPoint
   * 5)使用@After註解表明是最終通知
   *   參數:
   *     value:指定切入點表達式
   */
    @After(value = "mycut()")
    public void myAfter(){
        System.out.println("最終通知的功能........");
    }

    @Before(value = "mycut()")
    public void myBefore(){
        System.out.println("前置通知的功能........");
    }

    @AfterReturning(value = "mycut()",returning = "obj")
    public void myAfterReturning(Object obj){
        System.out.println("後置通知的功能........");
    }
    @Around(value = "mycut()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("環繞通知中的前置通知的功能........");
        Object obj = pjp.proceed(pjp.getArgs());
        System.out.println("環繞通知中的後置通知的功能........");
        return obj;
    }

    @Pointcut(value = "execution(* com.bjpowernode.s04.*.*(..))")
    public void mycut(){}
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...