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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...