[Spring AOP 8] Spring AOP 源碼全流程總結

Spring AOP總結

更美觀清晰的版本在:Github

前面的章節:
[Spring AOP 1] 從零開始的JDK動態代理
[Spring AOP 2] 從零開始的CGLIB動態代理
[Spring AOP 3] Spring選擇代理
[Spring AOP 4] Spring AOP 切點匹配
[Spring AOP 5] 高級切面與低級切面:@Aspect vs Advisor
[Spring AOP 6] 靜態通知調用
[Spring AOP 7] 動態通知調用

我們以日常在Spring Boot中編寫AOP進行方法增強的代碼為例來整體梳理AOP背后到底發生了什么。我們需要:

  1. 配置類:開啟代理
  2. 切面類:這里準備了一個前置通知和一個環繞通知
  3. 目標類
  4. 啟動類
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 將會使用CGLIB代理
@ComponentScan(basePackages = "spring.aop.summarization")
public class AopConfig {}
@Slf4j
@Aspect
@Component
public class MyAspect {// 前置增強foo方法@Before("execution(* spring.aop.summarization.Target.foo(..))")public void beforeAdvice(JoinPoint joinPoint) {log.info("Foo is ready to do something...");}// 環繞增強bar方法@Around("execution(* spring.aop.summarization.Target.bar(..))")public Object executionTime(ProceedingJoinPoint joinPoint) throws Throwable {log.info("Bar is ready to do something...");long start = System.currentTimeMillis();Object result = joinPoint.proceed();long end = System.currentTimeMillis();log.info("Bar execution time: {}", end - start);return result;}
}
@Component
@Slf4j
public class Target {public void foo() {fooDoSomething();}public void bar() {barDoSomething();}public void fooDoSomething() {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}public void barDoSomething() {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);Target target = (Target) context.getBean("target"); // 獲得代理對象target.foo(); // 代理對象將調用增強了的方法target.bar();}
}

我們運行啟動類,可以看到預期的輸出結果:

  • foo方法被前置增強
  • bar方法被環繞增強
2025-05-08T11:16:12.382+01:00  INFO 13260 --- [           main] spring.aop.summarization.MyAspect        : Foo is ready to do something...
2025-05-08T11:16:13.384+01:00  INFO 13260 --- [           main] spring.aop.summarization.MyAspect        : Bar is ready to do something...
2025-05-08T11:16:14.386+01:00  INFO 13260 --- [           main] spring.aop.summarization.MyAspect        : Bar execution time: 1002

接下來,我們主要關注Spring AOP中發生的事情。

  1. 解析切面定義
    Spring 啟動時掃描所有 @Aspect 注解的類(如 MyAspect),并把帶有 @Before@Around@After 等方法標記的元信息提取出來,交給一個 ReflectiveAspectJAdvisorFactory 去生成“候選” Advisor

  2. 組裝低級 Advisor
    ReflectiveAspectJAdvisorFactory 會將每個切面方法分裝為一個 Pointcut + Advice

    1. 對于 @Before("…"),生成一個 AspectJExpressionPointcut 和一個 AspectJMethodBeforeAdvice,再封裝成一個 DefaultPointcutAdvisor
    2. 對于 @Around("…"),生成一個 AspectJExpressionPointcut 和一個 AspectJAroundAdvice,再封裝成另一個 DefaultPointcutAdvisor
    3. 所有這些 Advisor 都被當成候選切面緩存下來,等待后續匹配。
    4. 同時,Spring 也注冊了一個關鍵的 BeanPostProcessorAnnotationAwareAspectJAutoProxyCreator
      1. AnnotationAwareAspectJAutoProxyCreator后續會根據切面類型自動生成代理對象
  3. 容器刷新 & BeanPostProcessor 注冊
    SpringApplication.run(...) 完成掃描和注冊后,容器會把 AnnotationAwareAspectJAutoProxyCreator 等所有 BeanPostProcessor 都注冊到生命周期中。

  4. Bean 實例化與初始化(省略細節)
    對每一個普通 Bean(比如:Target),

    1. Spring會用構造器創建實例并進行依賴注入;
      • 如果Bean沒有循環依賴,那么AnnotationAwareAspectJAutoProxyCreator創建代理對象的時機在Bean初始化后
      • 如果Bean被檢測到有循環依賴,那么AnnotationAwareAspectJAutoProxyCreator創建代理對象的時機在依賴注入前
    2. 進行Bean的后處理;
    3. 進入AOP代理邏輯;
  5. 自動代理 (wrapIfNecessary)
    在Bean的后處理中:

    1. AnnotationAwareAspectJAutoProxyCreator#wrapIfNecessary判斷
      • 這個類是不是基礎設施(切面本身、Advisor、Advice 等)如果是,跳過;否則執行findEligibleAdvisors()
    2. 調用 findEligibleAdvisors():它會拿之前緩存的所有候選 Advisor,對每一個執行靜態匹配,找到所有匹配當前 Bean 的切面;
    3. 若結果不為空,就新建一個 ProxyFactory,決定用 JDK 代理還是 CGLIB,給它設置目標對象和接口/類信息;
      • proxyTargetClass = false && 目標實現接口:JDK
      • proxyTargetClass = false && 目標未實現接口:CGLIB
      • proxyTargetClass = true:CGLIB
    4. 把上一步過濾出的 Advisor 全部加到 ProxyFactory
    5. 調用 proxyFactory.getProxy(),生成代理對象,并替換掉容器中原來的 Bean 引用。
  6. 代理對象注入
    以后別的 Bean 依賴 Target 時,Spring 注入的都是上面生成的代理(JdkDynamicAopProxyObjenesisCglibDynamicAopProxy),而不是直接的 new Target()

  7. 運行時方法調用 & 攔截鏈執行
    當調用 target.foo()target.bar()時:

    1. 代理對象攔截調用,進入 JdkDynamicAopProxy#invokeCglibAopProxy#intercept
      1. 先執行AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice()
        • 將所有通知統一轉換為靜態通知
        • 或者拿到動態通知,但我們這個例子中沒有動態通知
      2. 再先根據 Advisor 列表為該方法構建 MethodInterceptor
        • ExposeInvocationInterceptor會創建一個最外圍的ADVISOR切面
        • 同時會將調用鏈存入自己的ThreadLocal
    2. 調用 ReflectiveMethodInvocation.proceed(),沿鏈執行(遞歸):
      • Before Advice@Before)── 執行 beforeAdvice()
      • Around Advice@Around)── 調用 proceed() 前邏輯;
      • 目標方法Target#foo / bar)實際上被調用;
      • 開始一層層退出,Around Advice后邏輯被執行
      • 退出Before Advice
    3. 鏈條執行完畢,最終結果返回給調用者。

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

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

相關文章

C#高級編程:加密解密

在數字化時代,數據安全是每個應用程序都必須重視的環節。無論是用戶的個人信息、敏感的商業數據,還是重要的系統配置,都需要得到妥善的保護。C# 作為一種廣泛應用的編程語言,提供了豐富且強大的加密解密功能,幫助開發者構建安全可靠的應用。本文將深入探討 C# 高級編程中的…

基于運動補償的前景檢測算法

這段代碼實現了基于運動補償的前景檢測算法。 主要功能包括: 運動補償模塊:使用基于網格的 KLT 特征跟蹤算法計算兩幀之間的運動,然后通過單應性變換實現幀間運動補償。前景檢測模塊:結合兩幀運動補償結果,通過幀間差…

使用matlab進行數據擬合

目錄 一、工作區建立數據 二、曲線擬合器(在"APP"中) 三、曲線擬合函數及參數 四、 在matlab中編寫代碼 一、工作區建立數據 首先,將數據在matlab工作區中生成。如圖1所示: 圖 1 二、曲線擬合器(在"APP"中) 然后,…

Playwright 安裝配置文件詳解

Playwright 安裝&配置文件詳解 環境準備 Node.js 14.0(推薦 LTS 版本)npm(推薦使用最新版)支持 Windows、macOS、Linux 一步到位的官方推薦安裝方式 1. 進入你的項目目錄 # Windows cd 路徑\到\你的項目 # macOS/Linux cd…

中國古代史4

東漢 公元25年,劉秀建立東漢,定都洛陽,史稱光武中興 白馬寺:漢明帝時期建立,是佛教傳入中國后興建的第一座官辦寺院,有中國佛教的“祖庭”和“釋源”之稱,距今1900多年歷史 班超—西域都護—投…

springboot + mysql8降低版本到 mysql5.7

springboot mysql8降低版本到 mysql5.7 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency>spring:datasource:driverClassName: com.mysql.jdbc.D…

4.4java常用類

在 Java 中&#xff0c;System 和 Runtime 類都是 java.lang 包下非常重要的類&#xff0c;它們提供了與系統交互以及管理 Java 虛擬機&#xff08;JVM&#xff09;運行時環境的功能。 System 類 System 類包含了一些有用的類字段和方法&#xff0c;它不能被實例化&#xff0…

【嵌入式筆記】Modbus TCP

1.概述 定義&#xff1a;Modbus TCP 是 Modbus 協議的變體&#xff0c;基于 TCP/IP 協議棧&#xff0c;用于通過以太網實現工業設備間的通信。 背景&#xff1a;由施耐德電氣&#xff08;原 Modicon 公司&#xff09;在 1999 年發布&#xff0c;將傳統的 Modbus RTU/ASCII 適配…

《解鎖React Native與Flutter:社交應用啟動速度優化秘籍》

React Native和Flutter作為當下熱門的跨平臺開發框架&#xff0c;在優化應用啟動性能方面各有千秋。今天&#xff0c;我們就深入剖析它們獨特的策略與方法。 React Native應用的初始包大小對啟動速度影響顯著。在打包階段&#xff0c;通過精準分析依賴&#xff0c;去除未使用的…

R語言學習--Day02--實戰經驗反饋

最近在做需要用R語言做數據清洗的項目&#xff0c;在網上看再多的技巧與語法&#xff0c;都不如在項目中實戰學習的快&#xff0c;下面是我通過實戰得來的經驗。 判斷Rstudio是否卡死 很多時候&#xff0c;我們在運行R語言代碼時&#xff0c;即使只是運行框選的幾行代碼&#…

How Sam‘s Club nudge customers into buying more

Here’s how Sam’s Club (or similar warehouse memberships) nudge customers into buying more: It’s a classic psychological strategy rooted in sunk cost fallacy and loss aversion. 1. Prepaid Membership Creates a “Sunk Cost” Once you’ve paid the annual …

OpenHarmony系統HDF驅動開發介紹(補充)

一、HDF驅動簡介 HDF&#xff08;Hardware Driver Foundation&#xff09;驅動框架&#xff0c;為驅動開發者提供驅動框架能力&#xff0c;包括驅動加載、驅動服務管理、驅動消息機制和配置管理。 簡單來說&#xff1a;HDF框架的驅動和Linux的驅動比較相似都是由配置文件和驅動…

自然語言處理 (NLP) 入門:NLTK 與 SpaCy 的初體驗

自然語言處理入門&#xff1a;NLTK 與 SpaCy 的初體驗 在當今數字化飛速發展的浪潮中&#xff0c;自然語言處理&#xff08;NLP&#xff09;已經成為了極具熱度的技術領域。自然語言處理的核心目標是讓計算機能夠理解、分析并生成人類語言&#xff0c;其應用場景極為廣泛&…

LLaVA:開源多模態大語言模型深度解析

一、基本介紹 1.1 項目背景與定位 LLaVA(Large Language and Vision Assistant)是由Haotian Liu等人開發的開源多模態大語言模型,旨在實現GPT-4級別的視覺-語言交互能力。該項目通過視覺指令微調技術,將預訓練的視覺編碼器與語言模型深度融合,在多個多模態基準測試中達到…

如何利用大模型對文章進行分段,提高向量搜索的準確性?

利用大模型對文章進行分段以提高向量搜索準確性,需結合文本語義理解、分塊策略優化以及向量表示技術。以下是系統性的解決方案: 一、分塊策略的核心原則 語義完整性優先 分塊需確保每個文本單元在語義上獨立且完整。研究表明,當分塊內容保持單一主題時,向量嵌入的語義表征能…

Java高頻面試之并發編程-17

volatile 和 synchronized 的區別 在 Java 并發編程中&#xff0c;volatile 和 synchronized 是兩種常用的同步機制&#xff0c;但它們的適用場景和底層原理有顯著差異。以下是兩者的詳細對比&#xff1a; 1. 核心功能對比 特性volatilesynchronized原子性不保證復合操作的原…

技術債務積累,如何進行有效管理

識別和評估技術債務、明確技術債務的優先級、制定系統的還債計劃、持續監控與預防技術債務產生是有效管理技術債務積累的重要策略。其中尤其要注重識別和評估技術債務&#xff0c;只有準確識別技術債務的種類和嚴重程度&#xff0c;才能制定出高效且有針對性的解決方案&#xf…

安裝windows版本的nacos

一、下載nacos安裝包 瀏覽器搜索nacos&#xff0c;進入nacos官網 https://nacos.io/docs/latest/overview/ 選擇下載windows版本的nacos 二、解壓縮 三、進入bin目錄&#xff0c;cmd命令行窗口 四、啟動nacos 查看日志 五、打開可視化頁面查看 以上&#xff0c;就是安裝wind…

小結:Android系統架構

https://developer.android.com/topic/architecture?hlzh-cn Android系統的架構&#xff0c;分為四個主要層次&#xff1a;應用程序層、應用框架層、庫和運行時層以及Linux內核層。&#xff1a; 1. 應用程序層&#xff08;Applications&#xff09; 功能&#xff1a;這一層包…

鴻蒙5.0項目開發——鴻蒙天氣項目的實現(歡迎頁)

【高心星出品】 文章目錄 歡迎頁面效果數據字典創建數據庫表格Splash頁面頁面功能歡迎頁代碼亮點 項目按照從數據庫連接層–視圖層–業務邏輯層這種三層架構開發&#xff0c;所以先設計了數據庫表格的結構&#xff0c;在EntryAbility中創建表格。 歡迎頁面效果 數據字典 sear…