深度解析 Spring 源碼:解密AOP切點和通知的實現機制

在這里插入圖片描述

文章目錄

  • 深度解析 Spring 源碼:解密AOP切點和通知的實現機制
    • 一、Spring AOP的基礎知識
      • 1.1 AOP的核心概念:切點、通知、切面等
      • 1.2 Spring AOP與傳統AOP的區別和優勢
    • 二、深入分析切點和通知的實現
      • 2.1 研究 Pointcut 接口及其實現類
        • 2.1.1 Pointcut 接口
        • 2.1.2 AspectJExpressionPointcut類
        • 2.1.3 NameMatchMethodPointcut類
      • 2.2 探討 Advice 接口及其實現類
        • 2.2.1 通知類型
        • 2.2.2 MethodBeforeAdvice接口
        • 2.2.3 AspectJMethodBeforeAdvice類
    • 三、實際與運用
      • 3.1 代碼展示Spring AOP的用法和配置方式
      • 3.2 結合實例說明切點和通知如何在實際項目中應用

深度解析 Spring 源碼:解密AOP切點和通知的實現機制

一、Spring AOP的基礎知識

1.1 AOP的核心概念:切點、通知、切面等

使用AOP可以將那些與核心業務邏輯無關但又分散在各處的橫切關注點(如日志記錄、性能監控、事務管理等)抽離出來,通過切面的方式進行統一管理和維護,從而提高了代碼的模塊化程度、可維護性和可擴展性。

  1. 切點:切點是在應用程序中定義的一組條件,用于確定何處插入橫切關注點。在Java中,切點通常是由表達式來定義的,這些表達式可以匹配到程序中的特定方法調用或者其他程序執行的位置。例如,一個切點可以定義為匹配所有service包下的方法調用。切點實際上是AOP在代碼中的具體位置。
  2. 通知:通知是在切點上執行的代碼,它定義了在何時、何地以及如何執行橫切邏輯。通知可以是在切點之前執行(Before advice)、在切點之后執行(After advice)、在方法返回值后執行(After-returning advice)、在方法拋出異常后執行(After-throwing advice)以及環繞執行(Around advice)等不同類型。
  3. 切面:切面是橫切關注點的模塊化實現,它將通知和切點組合在一起。一個切面是一個類,它包含了多個通知和切點的定義。在實際應用中,切面可以被看作是一種特殊的類,它提供了一種方式來定義橫切關注點,并將其與主要業務邏輯分離開來。

關系圖

在這里插入圖片描述

1.2 Spring AOP與傳統AOP的區別和優勢

Spring AOP相對于傳統AOP來說更加輕量級和易用,適合于大部分應用場景下的AOP需求。傳統AOP則提供了更豐富的功能和更靈活的配置選項,適用于對AOP功能有更高要求的特定場景。

實現與擴展方面的區別和優勢

  1. 實現方式
    • 傳統AOP:傳統的AOP實現通常是通過靜態代理或者動態代理來實現的。靜態代理要求在編譯時就確定代理對象,而動態代理則是在運行時生成代理對象。傳統AOP的實現需要程序員手動編寫代理類或使用代碼生成工具,相對比較繁瑣。
    • Spring AOP:Spring AOP是基于動態代理實現的,它利用了JDK動態代理和CGLIB動態代理來在運行時生成代理對象。Spring AOP通過配置來定義切點和通知,而無需手動編寫代理類,簡化了AOP的實現。
  2. 依賴關系
    • 傳統AOP:傳統的AOP實現通常依賴于特定的AOP框架,如AspectJ。使用傳統AOP需要引入獨立的AOP框架,并學習其專門的語法和配置方式。
    • Spring AOP:Spring AOP是Spring框架的一部分,與Spring IoC容器緊密集成。因此,使用Spring AOP無需引入額外的依賴,而是直接利用Spring的核心功能實現AOP,簡化了項目的依賴管理和配置。
  3. 功能擴展
    • 傳統AOP:傳統AOP通常提供了更豐富的功能和更靈活的配置選項,如支持更多類型的通知(如引入通知)、更細粒度的切點定義等。
    • Spring AOP:Spring AOP相對于傳統AOP來說功能較為簡單,只支持方法級別的切面,通知類型也相對較少。但Spring AOP提供了與Spring框架無縫集成的優勢,能夠與Spring的IoC容器和其他功能(如事務管理、異常處理等)無縫配合,使得AOP的應用更加方便和統一。

二、深入分析切點和通知的實現

2.1 研究 Pointcut 接口及其實現類

2.1.1 Pointcut 接口

接口 Pointcut 表示一個切點,可以確定哪些類和方法應該被包含在一個切面中。通過提供類過濾器方法匹配器,允許開發者定義更加精確的切點條件。

在這里插入圖片描述

2.1.2 AspectJExpressionPointcut類

本文僅僅分析用于確定給定方法是否匹配切點條件的matches方法,對于實現類的其它方法,讀者感興趣可自行解讀,亦可以期待后續的博文。

第一個 matches 方法位于 ShadowMatch 對象上,用于判斷連接點是否匹配切點條件。這個方法是由 ShadowMatch 類提供的,用于執行切點表達式與目標方法的匹配邏輯。

在這里插入圖片描述

第二個 matches 方法位于 JoinPointMatch 對象上,用于判斷連接點的匹配狀態。這個方法是由 JoinPointMatch 類提供的,用于判斷連接點是否成功匹配了切點表達式。

在這里插入圖片描述

2.1.3 NameMatchMethodPointcut類

檢查給定的方法名是否與列表中的任何一個方法名匹配。

在這里插入圖片描述

用于判斷一個字符串是否符合給定的模式,源碼結合切面表達式看易于理解。

/*** execution(): 這是最常用的切入點函數,在方法執行時觸發切入點* 切入點函數參數: 包括方法的訪問修飾符、返回類型、類名、方法名和參數列表等* 通配符: 例如*用于匹配任意字符,..用于匹配任意數量的參數等* 邏輯運算符: 例如&&表示與,||表示或,!表示非*/
@Pointcut("execution(* com.example.service.*.*(..))")
private void serviceMethods() {}

在這里插入圖片描述

2.2 探討 Advice 接口及其實現類

Advice 接口有多個子接口,如 MethodBeforeAdviceAfterReturningAdviceThrowsAdvice 等。

本文解讀前置通知,其它通知讀者感興趣可以自行去了解。

2.2.1 通知類型

通知類型可以分為以下幾種

  1. 前置通知(Before Advice)
    • 在目標方法執行之前執行的邏輯。
    • 實現了 org.springframework.aop.MethodBeforeAdvice 接口的通知稱為前置通知。
    • 通常用于執行一些準備工作,比如權限檢查、日志記錄等。
  2. 后置通知(After Returning Advice)
    • 在目標方法成功執行之后執行的邏輯。
    • 實現了 org.springframework.aop.AfterReturningAdvice 接口的通知稱為后置通知。
    • 通常用于處理方法的返回值或清理工作。
  3. 環繞通知(Around Advice)
    • 在目標方法執行前后都能執行的邏輯,可以控制目標方法的執行。
    • 實現了 org.aopalliance.intercept.MethodInterceptor 接口的通知稱為環繞通知。
    • 通常用于包裝目標方法的調用,實現額外的邏輯,比如性能監控、事務管理等。
  4. 拋出異常通知(After Throwing Advice)
    • 在目標方法拋出異常后執行的邏輯。
    • 實現了 org.springframework.aop.ThrowsAdvice 接口的通知稱為拋出異常通知。
    • 通常用于異常處理、日志記錄等。
  5. 引介通知(Introduction Advice)
    • 在不修改目標類的前提下,為目標類添加新的方法或字段。
    • 實現了 org.springframework.aop.IntroductionInterceptor 接口的通知稱為引介通知。
    • 通常用于向現有類添加新的行為。
2.2.2 MethodBeforeAdvice接口

用于在目標方法執行之前執行某些操作。

在這里插入圖片描述

2.2.3 AspectJMethodBeforeAdvice類

主要作用是在目標方法執行前執行一些額外的操作。

在這里插入圖片描述

三、實際與運用

3.1 代碼展示Spring AOP的用法和配置方式

Spring AOP是 Spring 框架的一個重要特性,允許以聲明性方式來定義橫切關注點,如日志記錄、性能監控、事務管理等,而無需修改業務邏輯代碼。

Spring AOP 的使用XML形式的Demo,包括配置方式和用法

  1. 添加依賴
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.9</version> <!-- 版本號可以根據實際情況調整 -->
</dependency>
  1. 創建切面類
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;/*** @Aspect 注解表示這是一個切面類* @Before 注解表示在目標方法執行之前執行通知* 切入點表達式指定了切入點為 com.example.service 包中的所有類的所有方法*/
@Aspect
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void logBefore() {System.out.println("Logging before method execution...");}
}
  1. 配置 Spring Bean
<!-- Spring 配置文件中聲明切面類為一個 Spring Bean -->
<bean id="loggingAspect" class="com.example.aspect.LoggingAspect"/>
  1. 啟用 Spring AOP
<!-- 在 Spring 配置文件中啟用 Spring AOP -->
<aop:aspectj-autoproxy/>
  1. 創建業務類
package com.example.service;public class MyService {public void doSomething() {System.out.println("Doing something...");}
}
  1. 測試
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.service.MyService;public class Main {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");MyService myService = (MyService) context.getBean("myService");myService.doSomething();}
}

3.2 結合實例說明切點和通知如何在實際項目中應用

以訂單創建日志記錄的Demo:

  1. 定義訂單服務接口
public interface OrderService {void createOrder(Order order);
}
  1. 實現訂單服務
@Service
public class OrderServiceImpl implements OrderService {@Overridepublic void createOrder(Order order) {// 創建訂單的具體邏輯System.out.println("訂單已創建:" + order);}
}
  1. 創建訂單實體類
public class Order {private Long id;private String customerName;private double amount;// 省略 getter 和 setter 方法
}
  1. 創建日志切面
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;/*** 在LoggingAspect切面類上添加了@Aspect和@Component注解,用于告訴Spring這是一個切面類,并將其納入Spring容器管理*/
@Aspect
@Component
public class LoggingAspect {/*** 使用了@Before注解來定義了一個前置通知* 執行OrderService接口的createOrder方法之前被觸發* 切入點表達式指定切入點為OrderService接口的createOrder方法*/@Before("execution(* com.example.service.OrderService.createOrder(..)) && args(order)")public void logBefore(Order order) {System.out.println("訂單已創建,訂單ID:" + order.getId() + ",客戶姓名:" + order.getCustomerName());System.out.println("記錄訂單創建日志...");}
}
  1. AppConfig配置類
/*** 使用了@Configuration、@ComponentScan和@EnableAspectJAutoProxy注解來啟用Spring AOP和組件掃描*/
@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
  1. 測試
public class Main {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);OrderService orderService = context.getBean(OrderService.class);Order order = new Order();order.setId(1L);order.setCustomerName("Alice");order.setAmount(100.0);orderService.createOrder(order);}
}// 輸出結果
訂單已創建,訂單ID1,客戶姓名:Alice
記錄訂單創建日志...
訂單已創建:Order{id=1, customerName='Alice', amount=100.0}

古人學問無遺力,少壯工夫老始成

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/12848.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/12848.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/12848.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

powershell 防止休眠或屏幕關閉并定時截屏保存

powershell 防止休眠或屏幕關閉 01 前言 因工作需要&#xff0c;需要在用戶的機器上進行操作&#xff0c;有些工作比較耗時、耗CPU&#xff0c;配置也不高&#xff0c;因而就不能用這臺機器同時干太多活&#xff0c;又不能干盯著啥也干不了&#xff0c;但是一段時間不操作&am…

鞏固學習9

show-me-the-code題目001 #做為 Apple Store App 獨立開發者&#xff0c;你要搞限時促銷&#xff0c;為你的應用生成激活碼&#xff08;或者優惠券&#xff09;&#xff0c;使用 Python 如何生成 200 個激活碼&#xff08;或者優惠券&#xff09;&#xff1f; import random a…

延遲隊列有哪些

延遲隊列 與時間相關場景的應用,經常用于延后多少時間執行什么任務。 java 自帶延遲隊列 class Solution {public static void main(String[] args) throws InterruptedException {DelayQueue<DelayMealTask> queue = new DelayQueue<>();DelayMealTask task =…

MySQL存儲過程練習

DDL CREATE TABLE student (id int(11) NOT NULL AUTO_INCREMENT COMMENT 學號,createDate datetime DEFAULT NULL,userName varchar(20) DEFAULT NULL,pwd varchar(36) DEFAULT NULL,phone varchar(11) DEFAULT NULL,age tinyint(3) unsigned DEFAULT NULL,sex char(2) DEFAU…

數據庫審計系統Yearning使用筆記

一、啟動 1、初始化MySQL 啟動mysql docker run -d --namemysql -p 3306:3306 -e MYSQL_ROOT_PASSWORDroot mysql:5.7創建數據庫&#xff0c;鏈接數據庫并執行以下創建庫的腳步&#xff0c;注意字符集 create database yearning char set utf8mb42、啟動Yeelabs 需要執行…

CDGA|揭秘移動物聯網數據治理秘訣,輕松提升數據質量,賦能智慧未來

在數字化浪潮洶涌的今天&#xff0c;移動物聯網作為連接物理世界與數字世界的橋梁&#xff0c;其數據治理的重要性日益凸顯。高質量的數據不僅是企業決策的基石&#xff0c;更是推動行業智能化、精細化發展的關鍵。本文將為您揭秘移動物聯網數據治理的技巧&#xff0c;助您輕松…

如何設計實用的ITSM自助服務臺

在現代IT服務管理&#xff08;ITSM&#xff09;領域中&#xff0c;自助服務臺已成為IT運維環境的核心組件。它作為企業內部信息中心與其他部門用戶之間的橋梁&#xff0c;一個以用戶為中心的平臺&#xff0c;更注重用戶的自主性和自助能力&#xff0c;使用戶能夠直接訪問所需的…

微軟宣布GPT-4o模型,可在 Azure OpenAI上使用

5月14日&#xff0c;微軟在官網宣布&#xff0c;OpenAI最新發布的多模態模型GPT-4o&#xff0c;可以在 Azure OpenAI 云服務中使用。 據悉&#xff0c;GPT-4o支持跨文本、視頻、音頻多模態推理&#xff0c;例如&#xff0c;通過GPT-4o打造一個AI助手&#xff0c;用于輔導孩子解…

halcon學習之形狀匹配

算子 create_shape_model&#xff08;&#xff09; 創建一個用于匹配的形狀模型 create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID) 參數 Template&#xff1a; NumLevels&#…

基于NIOS-II軟核流水燈和串口通信實現

文章目錄 一、創建工程二、系統設計1. 在 “component library” 標簽欄中找到 “Nios II Processor” 后點擊 Add2. 在 ”Component Library” 標簽欄中的查找窗口輸入 jtag 找到 ”JTAG UART ”&#xff0c;然后點擊 Add3. 添加片上存儲器 On-Chip Memory(RAM)核4. 查找窗口輸…

做簡單易用的GIS資源管理軟件

在室外資源管理領域&#xff0c;采用基于GIS的解決方案已成為主流趨勢&#xff0c;旨在實現資源的高效利用和管理。GIS技術結合資源對象的規劃、定位和監控&#xff0c;為企業提供全面的管理方案&#xff0c;從而優化資源使用、提高運營效率和降低成本。 然而&#xff0c;許多資…

龍迅LT8911EX LVDS橋接到EDP,支持4K30HZ分辨率

龍迅LT8911EX描述&#xff1a; Lontium LT8911EX是LVDS到eDP轉換器&#xff0c;具有單端口或雙端口可配置的LVDS接收器&#xff0c;有1個時鐘通道和最多8個數據通道&#xff0c;每個數據通道最大運行1.2Gbps&#xff0c;最大輸入帶寬為9.6Gbps。轉換器將輸入LVDS數據去序列化&…

OpenNJet產品體驗:探索無限可能

文章目錄 前言一、OpenNJet是什么&#xff1f;二、OpenNJet特性和優點三、OpenNJet功能規劃四、OpenNJet快速上手五、OpenNJet的使用總結 前言 現代社會網絡高速發展&#xff0c;同時也迎來了互聯網發展的高峰&#xff0c;OpenNJet作為一個基于NGINX的面向互聯網和云原生應用提…

掏心經驗分享,軟考中項0基礎入門篇!

想備考下半年中項&#xff08;系統集成項目管理工程師&#xff09;的朋友&#xff0c;不知道如何了解軟考中項&#xff0c;今天給大家整理一篇關于我自己在備考軟考時的一些考量和踩過的一些坑。&#xff08;無廣&#xff0c;放心看&#xff09; 很多小伙伴總是聽大家說軟考中…

NGM-SLAM:首創融合神經輻射場子圖的3DGS-SLAM,問鼎SOTA!

論文標題&#xff1a; NGM-SLAM: Gaussian Splatting SLAM with Radiance Field Submap 論文作者&#xff1a; Mingrui Li, Jingwei Huang, Lei Sun Aaron, Xuxiang Tian, Tianchen Deng, Hongyu Wang 導讀&#xff1a; 3DGS技術因其性能卓越而備受關注&#xff0c;3DGS-SLA…

uniapp微信小程序通過螢石云接入海康攝像機

需求&#xff1a;在uniapp微信小程序上查看海康威視的攝像機監控視頻和和操作攝像機拍攝方向 在螢石云接入海康攝像機設備&#xff0c;由于不同品牌設備在不同時間段接入方式可能不一致&#xff0c;具體接入方式查看官方文檔或咨詢官方客服。 海康攝像機官方客服熱線&#xf…

stack、queue、priority_queue以及仿函數

我們上次對std中的list進行實現&#xff0c;今天我們要實現stack、queue、priority_queue以及仿函數。 目錄 stack堆堆的框架構造函數push插入pop刪除size()大小empty()判斷空top()取棧頂的元素 queue隊列隊列框架問題&#xff1a; 這里我們為什么用deque? 插入刪除取頭數據取…

AI交互數字人賦能農業數字化、智能化推廣營銷

2024陵水荔枝文化節上“數字新農人”陵小荔身著黎族服飾、佩戴銀器亮相開幕式現場&#xff0c;AI交互數字人生動地以互動式推介和歌舞等形式&#xff0c;帶領賓客們了解陵水荔枝的發展歷程、產業布局、未來愿景等。如今&#xff0c;越來越多農產品品牌通過3D虛擬數字人定制&…

Redis和數據庫能做到強一致嗎?

在現代軟件系統中&#xff0c;數據一致性是至關重要的&#xff0c;特別是對于需要處理大量并發請求和實時數據的系統。Redis 和數據庫都是常見的數據存儲解決方案&#xff0c;但它們在保證數據一致性方面有著不同的特點和限制。 本文將深入探討 Redis 和數據庫是否能夠做到強一…

最詳細的提單知識總結 | 數字貿易綜合服務平臺 | 箱訊科技

在外貿交易中&#xff0c;國際物流是必不可少的一個步驟。國際物流掌控好&#xff0c;就等于把貨物牢牢握在手心&#xff0c;不怕貨財兩空。 本期將向大家介紹正本提單、電放提單、海運單三種國際海運放貨方式以及區分它們的方法。 超實用&#xff01;外貿人趕緊收藏~ 正本提…