spring AOP總結

来源:https://www.cnblogs.com/xshan/archive/2023/11/04/17808980.html
-Advertisement-
Play Games

一、概念 AOP面向切麵編程,一種編程範式 二、作用 在不改動原始設計(原代碼不改動)的基礎上為方法進行功能增強(即增加功能) 三、核心概念 1、代理(Proxy):SpringAOP的核心本質是採用代理模式實現的 2、連接點(JoinPoint):在SpringAOP中,理解為任意方法的執行 3、 ...


一、概念

  AOP面向切麵編程,一種編程範式

二、作用

  在不改動原始設計(原代碼不改動)的基礎上為方法進行功能增強(即增加功能)

三、核心概念

  1、代理(Proxy):SpringAOP的核心本質是採用代理模式實現的

  2、連接點(JoinPoint):在SpringAOP中,理解為任意方法的執行

  3、切入點(Pointcut):匹配連接點的式子,也是具有共性功能的方法描述

  4、通知(Advice):若幹個方法的共性功能,在切入點處執行,最終體現為一個方法

  5、切麵(Aspect):描述通知與切入點的對應關係

  6、目標對象(Target):被代理的原始對象成為目標對象

四、快速開始

  1、導入相關依賴

  由於導入spring-context時會自動導入spring的AOP包所以,這裡只用導入aspectjweaver即可。

  在pom.xml文件中導入

 

    <dependencies>
   <!--spring核心依賴,會將spring-aop傳遞進來--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.29</version> </dependency>
    <!--切入點表達式依賴,目的是找到切入點方法,也就是找到要增強的方法--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.19</version> </dependency> </dependencies>

 

  2、定義dao介面與實現類

  在dao下麵創建BookDao介面類文件

public interface BookDao {
    public void save();
    public void update();
}

  在dao下麵創建impl文件夾,裡面創建BookDao的實現類BookDaoImpl

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println(System.currentTimeMillis());
        System.out.println("book dao save ...");
    }
    public void update(){
        System.out.println("book dao update ...");
    }
}

  3、定義通知類,製作通知方法

  創建aop文件夾,併在下麵創建類MyAdvice。

package com.itheima.aop;

import org.springframework.stereotype.Component;

@Component
public class MyAdvice {
    public void method() {
        System.out.println(System.currentTimeMillis());
        System.out.println("進行增強功能");
    }
}

  4、定義切入點表達式、配置切麵(綁定切入點與通知關係)

package com.itheima.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
//設置切入點,@Pointcut註解要求配置在方法上方
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
//設置在切入點pt()的前面運行當前操作(前置通知)
@Before("pt()")
public void method() {
System.out.println(System.currentTimeMillis());
System.out.println("進行增強功能");
}
}

  5、在配置類中進行Spring註解包掃描和開啟AOP功能  

  創建config文件夾,創建Spring的配置文件。

package com.itheima.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

// 告知spring這是個配置類
@Configuration
// 掃描指定包
@ComponentScan(basePackages = {"com.itheima"})
// 開啟aop,告知spring開啟使用註解的方式開啟aop
@EnableAspectJAutoProxy
public class SpringConfig {

}

  6、創建啟動文件

  在項目目錄下創建啟動類文件,App文件

package com.itheima;

import com.itheima.config.SpringConfig;
import com.itheima.dao.BookDao;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 創建容器對象, 傳入配置類
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 2. 從容器中獲取對象
        BookDao bookDao = context.getBean(BookDao.class);
        // 3. 執行方法
//        bookDao.save();
        bookDao.update();
    }
}

  7、最終項目目錄結構

 

五、切入點表達式

  1、切入點:要進行增強的方法

  2、切入點表達式:要進行增強的方法的描述方式

    切入點表達式標準格式:動作關鍵字(訪問修飾符   返回值   包名.類/介面名.方法名(參數)異常名)

execution(* com.testweb.service.*Service.*(..))

  切入點表達式描述通配符

    作用:用於快速描述,範圍描述

    * :匹配任意符號(常用)

    ..:匹配多個連續的任意符號(常用)

    +:匹配子類型

  切入點表達式書寫技巧

    1、按標準規範開發

    2、查詢操作的返回值建議使用*匹配

    3、減少使用 .. 的形式描述包

    4、對介面進行描述,使用 * 表示模塊名,例如UserService的匹配描述為 *Service 

    5、方法名書寫保留動詞,例如get,使用 * 表示名詞,例如getById匹配描述為 getBy*

    6、參數根據實際情況靈活調整

 六、通知類型

  1、通知類型

    1、前置通知

    2、後置通知

    3、環繞通知(重點)

      *  環繞通知依賴形參ProceedingJoinPoint才能實現對原始方法的調用

      *  環繞通知可以隔離原始方法的調用執行

      *  環繞通知返回值設置為object類型

      *  環繞通知中可以對原始方法調用過程中出現的異常進行處理

    4、返回後通知

    5、拋出異常後通知

  2、AOP通知獲取數據

    1、獲取切入點方法的參數

      *  JoinPoint:適用於前置(@Before)、後置(@after)、返回後(@AfterReturning)、拋出異常後通知(@AfterThrowing)

package com.itheima.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
    //設置切入點,@Pointcut註解要求配置在方法上方
    @Pointcut("execution(* com.itheima.dao.BookDao.findName(..))")
    private void pt(){}
    //設置在切入點pt()的前面運行當前操作(前置通知)
    @Before("pt()")
    public void method(JoinPoint jp) {
        // 獲取參數
        for (Object o : jp.getArgs()) {
            System.out.println(o);
        }
        System.out.println(System.currentTimeMillis());
        System.out.println("進行增強功能");
    }
}

      * ProceedJointPoint:適用於環繞通知

package com.itheima.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
    //設置切入點,@Pointcut註解要求配置在方法上方
    @Pointcut("execution(* com.itheima.dao.BookDao.findName(..))")
    private void pt() {
    }

    //設置在切入點pt()的前面運行當前操作(前置通知)
    @Around("pt()")
    public Object method(ProceedingJoinPoint pjp) throws Throwable {
        // 獲取參數
        Object[] args = pjp.getArgs();
        // 修改原先的參數
        args[0] = 666;
        // 執行原方法,並傳入參數
        Object ret = pjp.proceed(args);
        System.out.println("進行增強功能");
        return ret;
    }
}

    2、獲取切入點方法返回值

      *  返回後通知

package com.itheima.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class MyAdvice {
    //設置切入點,@Pointcut註解要求配置在方法上方
    @Pointcut("execution(* com.itheima.dao.BookDao.findName(..))")
    private void pt() {
    }
    // 設置在原函數執行後執行當前操作(後置通知)
    // 如果有返回值,則可以寫成afterReturning(value = "pt()", returning = "ret"),使用ret接收原方法返回值
    // 如果有參數,則public void afterReturning(JoinPoint jp, Object ret),且JoinPoint jp,一定要在前面
    @AfterReturning(value = "pt()", returning = "ret")
    public void afterReturning(JoinPoint jp, Object ret) {
        // 獲取參數
        Object[] args = jp.getArgs();
        System.out.println("參數:" + Arrays.toString(args));
        System.out.println("返回值:" + ret);
        System.out.println("執行後置通知");
    }
}

      * 環繞通知

package com.itheima.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
    //設置切入點,@Pointcut註解要求配置在方法上方
    @Pointcut("execution(* com.itheima.dao.BookDao.findName(..))")
    private void pt() {
    }

    //設置在切入點pt()的前面運行當前操作(前置通知)
    @Around("pt()")
    public Object method(ProceedingJoinPoint pjp) throws Throwable {
        // 獲取參數
        Object[] args = pjp.getArgs();
        // 修改原先的參數
        args[0] = 666;
        // 執行原方法,並傳入參數,並用ret接收原方法返回值
        Object ret = pjp.proceed(args);
        System.out.println("進行增強功能");
        return ret;
    }
}

    3、獲取切入點方法運行異常信息

      * 拋出異常後通知

package com.itheima.aop;

import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class MyAdvice {
    //設置切入點,@Pointcut註解要求配置在方法上方
    @Pointcut("execution(* com.itheima.dao.BookDao.findName(..))")
    private void pt() {
    }

@AfterThrowing(value = "pt()", throwing = "e") public void afterThrowing(JoinPoint jp, Exception e) { // 獲取參數 Object[] args = jp.getArgs(); System.out.println("參數:" + Arrays.toString(args)); System.out.println("異常:" + e); System.out.println("執行異常後置通知"); } }

      * 環繞通知

package com.itheima.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
    //設置切入點,@Pointcut註解要求配置在方法上方
    @Pointcut("execution(* com.itheima.dao.BookDao.findName(..))")
    private void pt() {
    }//設置在切入點pt()的前面運行當前操作(前置通知)
    @Around("pt()")
    public Object method(ProceedingJoinPoint pjp) {
        // 獲取參數
        Object[] args = pjp.getArgs();
        // 修改原先的參數
        args[0] = 666;
        // 執行原方法,並傳入參數
        Object ret = null;
     // 獲取異常
try { ret = pjp.proceed(args); }catch (Throwable e) { e.printStackTrace(); } System.out.println("進行增強功能"); return ret; } }

 


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

-Advertisement-
Play Games
更多相關文章
  • Dart 3.0版本新增了很多新特性,包括有名的健全的空安全;同時針對類型(包括Mixin),除之前的abstract修飾符之外,還增加了base,final,interface和sealed等修飾符。今天我們來一起看下,這些類型修飾符,它們有哪些使用場景、使用時有哪些約束,和如何組合使用…… ...
  • Go類型嵌入介紹和使用類型嵌入模擬實現“繼承” 目錄Go類型嵌入介紹和使用類型嵌入模擬實現“繼承”一、獨立的自定義類型二、繼承三、類型嵌入3.1 什麼是類型嵌入四、介面類型的類型嵌入4.1 介面類型的類型嵌入介紹4.2 一個小案例五、結構體類型的類型嵌入5.1 結構體類型的類型嵌入介紹5.2 小案例 ...
  • Python 允許用戶輸入數據。這意味著我們可以向用戶詢問輸入。在 Python 3.6 中,使用 input() 方法來獲取用戶輸入。在 Python 2.7 中,使用 raw_input() 方法來獲取用戶輸入。以下示例要求用戶輸入用戶名,併在輸入用戶名後將其列印在屏幕上: Python 3.6 ...
  • OpenSSL 中的 `SSL` 加密是通過 `SSL/TLS` 協議來實現的。`SSL/TLS` 是一種安全通信協議,可以保障通信雙方之間的通信安全性和數據完整性。在 `SSL/TLS` 協議中,加密演算法是其中最核心的組成部分之一,SSL可以使用各類加密演算法進行密鑰協商,一般來說會使用`RSA`等... ...
  • 四大函數式介面(必備) 程式員:泛型、反射、註解、枚舉 新時代程式員:lambda表達式、鏈式編程、函數式介面、Stream流式計算 函數式介面:只有一個方法的介面 @FunctionalInterface public interface Runnable { public abstract vo ...
  • 推薦一個分散式圖資料庫Nebula Graph,萬億級數據,毫秒級延時 什麼是Nebula Graph Nebula Graph 是一款開源的、分散式的、易擴展的原生圖資料庫,能夠承載包含數千億個點和數萬億條邊的超大規模數據集,並且提供毫秒級查詢 什麼是圖資料庫 圖資料庫是專門存儲龐大的圖形網路並從 ...
  • 高精度的本質是將數字以字元串的形式讀入,然後將每一位分別存放入`int`數組中,通過模擬每一位的運算過程,來實現最終的運算效果。 ...
  • 對於手工計算來說,積分計算是非常困難的,對於一些簡單的函數,我們可以直接通過已知的積分公式來求解,但在更多的情況下,原函數並沒有簡單的表達式,因此確定積分的反函數變得非常困難。 另外,相對於微分運算來說,積分運算則具有更多的多樣性,包括不同的積分方法(如換元積分法、分部積分法等)和積分技巧,需要根據 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...