責任鏈模式原理詳解和源碼實例以及Spring AOP攔截器鏈的執行源碼如何使用責任鏈模式?

前言

??本文首先介紹了責任鏈的基本原理,并附帶一個例子說明責任鏈模式,確保能夠理解責任鏈的前提下,在進行Spring AOP執行責任鏈的源碼分析。責任鏈模式允許將多個處理對象連接成鏈,請求沿著鏈傳遞,直到被處理或結束。每個處理者可以選擇處理請求或傳遞給下一個。

??Spring AOP的攔截器鏈,攔截器或者過濾器鏈,都是典型的責任鏈應用。比如,當一個方法被調用時,多個攔截器按順序執行,每個攔截器可以決定是否繼續執行鏈中的下一個。

??深入Spring AOP的源碼部分,特別是攔截器鏈的執行過程。比如,在Spring AOP中,當調用一個被增強的方法時,會創建一個MethodInvocation對象,其中包含攔截器鏈。每個攔截器都是一個Advice,比如MethodInterceptor。這時候,責任鏈模式的應用可能體現在攔截器的依次調用上,每個攔截器處理完后調用下一個,直到最后一個攔截器執行實際的方法。

??具體分析Spring的源碼,比如ReflectiveMethodInvocation類的proceed方法。這個方法可能負責按順序調用攔截器鏈中的每個攔截器,直到所有攔截器處理完畢,最后調用目標方法。這個流程是否符合責任鏈模式的結構?是的,每個攔截器處理請求,并決定是否傳遞下去。

??可能還需要比較責任鏈模式的不同變體,比如純的責任鏈(每個處理者必須處理請求)和不純的(可以傳遞)。Spring AOP的攔截器鏈屬于后者,每個攔截器都可以選擇是否繼續傳遞,或者在處理前后執行某些操作,然后繼續傳遞。

??另外,Spring AOP的基本原理不在本文中介紹了,詳情請看以往文章,有更加詳細的表述,有理論和源碼的解析。文章:Spring AOP源碼解析

??實際應用場景本文也涉及到,如何自定義攔截器,如何調整攔截器鏈的順序,或者如何利用責任鏈模式實現類似的功能。這些實際應用案例可以增強回答的實用性。

??最后,確保回答結構清晰,先解釋責任鏈模式,再結合Spring源碼詳細說明,最后總結其優勢和應用場景。需要避免過于冗長的代碼分析,而是突出重點部分,比如關鍵類和方法的調用流程。


責任鏈模式原理詳解與源碼實例


一、責任鏈模式(Chain of Responsibility Pattern)原理

核心思想:將多個處理對象連成一條鏈,請求沿鏈傳遞,直到有一個處理對象處理它或鏈結束。每個處理對象可選擇處理請求或傳遞給下一個對象。

1. 模式結構
角色職責
Handler(抽象處理者)定義處理請求的接口,通常包含指向下一個處理者的引用(nextHandler)。
ConcreteHandler具體處理者,實現處理邏輯,或決定是否將請求傳遞到下一個處理者。
Request請求對象,封裝請求的上下文數據。
2. 類圖
+----------------+          +-------------------+
|   Handler      | <|-------| ConcreteHandlerA  |
+----------------+          +-------------------+
| +nextHandler   |          | +handleRequest()  |
| +handleRequest()|         +-------------------+
+----------------+                   ^|                            ||                            |
+-------------------+
| ConcreteHandlerB  |
+-------------------+
| +handleRequest()  |
+-------------------+
3. 執行流程
  1. 客戶端將請求發送到責任鏈的第一個處理者。
  2. 每個處理者決定是否處理該請求:
    • 若處理,則終止傳遞。
    • 若不處理,則調用 nextHandler.handleRequest()
  3. 請求沿鏈傳遞,直到被處理或鏈結束。

二、責任鏈模式源碼實例
1. 抽象處理者(Handler)
public abstract class Handler {protected Handler nextHandler; // 指向下一個處理者public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}public abstract void handleRequest(Request request);
}
2. 具體處理者(ConcreteHandler)
public class ConcreteHandlerA extends Handler {@Overridepublic void handleRequest(Request request) {if (canHandle(request)) {System.out.println("ConcreteHandlerA 處理請求: " + request.getData());} else if (nextHandler != null) {nextHandler.handleRequest(request); // 傳遞給下一個處理者}}private boolean canHandle(Request request) {return request.getType().equals("A");}
}public class ConcreteHandlerB extends Handler {@Overridepublic void handleRequest(Request request) {if (canHandle(request)) {System.out.println("ConcreteHandlerB 處理請求: " + request.getData());} else if (nextHandler != null) {nextHandler.handleRequest(request); // 傳遞給下一個處理者}}private boolean canHandle(Request request) {return request.getType().equals("B");}
}
3. 請求對象(Request)
public class Request {private String type; // 請求類型private String data; // 請求數據public Request(String type, String data) {this.type = type;this.data = data;}public String getType() { return type; }public String getData() { return data; }
}
4. 客戶端調用
public class Client {public static void main(String[] args) {// 創建責任鏈Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNextHandler(handlerB);// 發送請求Request request1 = new Request("A", "請求1");Request request2 = new Request("B", "請求2");handlerA.handleRequest(request1); // 由 ConcreteHandlerA 處理handlerA.handleRequest(request2); // 由 ConcreteHandlerB 處理}
}

輸出結果

ConcreteHandlerA 處理請求: 請求1
ConcreteHandlerB 處理請求: 請求2

三、Spring AOP 攔截器鏈中的責任鏈模式

Spring AOP 通過 攔截器鏈(Interceptor Chain) 實現方法增強(如事務、日志),其核心設計正是基于責任鏈模式。

1. 核心組件
組件職責
MethodInvocation封裝被代理方法的調用上下文(類似 Request)。
MethodInterceptor攔截器接口(類似 Handler),定義增強邏輯。
ReflectiveMethodInvocation具體責任鏈實現,管理攔截器鏈的調用順序。
2. 源碼解析
(1)攔截器鏈的創建

在生成代理對象時,Spring 會將所有匹配的攔截器(如 MethodInterceptor)按順序組合成鏈。

入口AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {// 獲取所有攔截器(包括事務、日志等)List<Object> interceptorList = new ArrayList<>();for (Advisor advisor : this.advisors) {if (advisor instanceof PointcutAdvisor) {// 匹配攔截器是否適用于當前方法if (((PointcutAdvisor) advisor).getPointcut().getMethodMatcher().matches(method, targetClass)) {interceptorList.add(advisor.getAdvice());}}}return interceptorList;
}
(2)責任鏈的觸發

代理對象調用方法時,觸發 ReflectiveMethodInvocation#proceed(),按順序執行攔截器鏈。該方法類似于遞歸執行,遞歸方法也是有終止條件的,請注意區分。

源碼ReflectiveMethodInvocation

public class ReflectiveMethodInvocation implements ProxyMethodInvocation {private final Object target;          // 目標對象private final Method method;          // 目標方法private final Object[] arguments;     // 方法參數private final List<Object> interceptorsAndDynamicMethodMatchers; // 攔截器鏈private int currentInterceptorIndex = -1; // 當前攔截器索引public Object proceed() throws Throwable {// 1. 所有攔截器執行完畢,調用原始方法if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}// 2. 獲取下一個攔截器Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);// 3. 執行攔截器邏輯if (interceptorOrInterceptionAdvice instanceof MethodInterceptor) {MethodInterceptor mi = (MethodInterceptor) interceptorOrInterceptionAdvice;return mi.invoke(this); // 將當前 MethodInvocation 傳遞給攔截器} else {// 動態匹配器處理(略)}}// 調用原始方法protected Object invokeJoinpoint() throws Throwable {return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);}
}
(3)攔截器的執行邏輯

每個 MethodInterceptor 攔截器決定是否繼續傳遞鏈(調用 proceed())或終止。

示例:Spring 事務攔截器 TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor {public Object invoke(MethodInvocation invocation) throws Throwable {// 1. 開啟事務TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);try {// 2. 繼續執行攔截器鏈(責任鏈傳遞)Object retVal = invocation.proceed();// 3. 提交事務commitTransactionAfterReturning(txInfo);return retVal;} catch (Throwable ex) {// 4. 回滾事務completeTransactionAfterThrowing(txInfo, ex);throw ex;}}
}

四、責任鏈模式在 Spring AOP 中的設計優勢
  1. 靈活擴展
    新增攔截器只需實現 MethodInterceptor 并注冊到鏈中,無需修改現有代碼。

  2. 邏輯解耦
    每個攔截器專注單一職責(如事務、日志),通過鏈式調用組合功能。

  3. 動態控制流程
    攔截器可決定是否繼續調用鏈(如權限校驗失敗時直接拋出異常終止流程)。

  4. 執行順序可控
    攔截器鏈的順序可通過 @Order 注解或實現 Ordered 接口調整。


五、實際應用場景與自定義攔截器
1. 自定義攔截器示例
public class LoggingInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("方法調用前: " + invocation.getMethod().getName());Object result = invocation.proceed(); // 繼續鏈System.out.println("方法調用后: " + invocation.getMethod().getName());return result;}
}
2. 配置攔截器鏈

在 Spring 配置中注冊攔截器:

<bean id="loggingInterceptor" class="com.example.LoggingInterceptor"/>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"/><aop:config><aop:advisor advice-ref="loggingInterceptor" order="1"/><aop:advisor advice-ref="transactionInterceptor" order="2"/>
</aop:config>
3. 執行順序

攔截器按 order 值從小到大依次執行:

LoggingInterceptor(前置日志) → TransactionInterceptor(事務管理) → 目標方法

六、總結
  • 責任鏈模式核心:解耦請求發送者與處理者,允許多個對象按鏈式處理請求。
  • Spring AOP 實現:通過 ReflectiveMethodInvocation 管理攔截器鏈,每個 MethodInterceptor 按責任鏈模式依次執行。
  • 優勢:靈活擴展、職責分離、動態流程控制。
  • 應用場景:事務管理、日志記錄、權限校驗、性能監控等切面功能。

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

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

相關文章

React 與 Vue 對比指南 - 上

React 與 Vue 對比指南 - 上 本文將展示如何在 React 和 Vue 中實現常見功能&#xff0c;從基礎渲染到高級狀態管理 Hello 分別使用 react 和 vue 寫一個 Hello World&#xff01; react export default () > {return <div>Hello World!</div>; }vue <…

大模型開發實戰篇7:語音識別-語音轉文字

語音識別大模型&#xff0c;是人工智能領域的一項重要技術&#xff0c;它能夠將人類的語音轉換為文本。近年來&#xff0c;隨著深度學習技術的不斷發展&#xff0c;語音識別大模型取得了顯著的進展&#xff0c;并在各個領域得到了廣泛應用。 主流語音識別大模型 目前&#xf…

向量的點乘的幾何意義

源自AI 向量的點乘&#xff08;Dot Product&#xff09;在幾何和圖形學中有重要的意義。它不僅是數學運算&#xff0c;還可以用來描述向量之間的關系。以下是點乘的幾何意義及其應用&#xff1a; 1. 點乘的定義 對于兩個向量 a 和 b&#xff0c;它們的點乘定義為&#xff1a;…

國產芯片汽車氣壓表pcba方案

汽車氣壓表的基本原理是利用氣壓傳感器將氣體氣壓轉換為電信號&#xff0c;再通過電子芯片電路進行處理傳輸&#xff0c;再將這些信息轉發給顯示屏顯示。常見的傳感器包括模擬氣壓傳感器和數字氣壓傳感器。其中&#xff0c;模擬氣壓傳感器是目前應用最廣泛的傳感器之一&#xf…

解鎖機器學習核心算法 | K -近鄰算法:機器學習的神奇鑰匙

一、引言 今天我們繼續學習機器學習核心算法 —— K - 近鄰&#xff08;K-Nearest Neighbors&#xff0c;簡稱 KNN&#xff09;算法。它就像是一位經驗豐富的 “老江湖”&#xff0c;以其簡單而又強大的方式&#xff0c;在眾多機器學習任務中占據著不可或缺的地位。 K - 近鄰…

如何在Windows 10操作系統中安裝并配置PHP集成軟件XAMPP

步驟1&#xff1a;下載XAMPP安裝包 訪問XAMPP官網&#xff1a; 打開瀏覽器&#xff0c;進入XAMPP官方網站&#xff1a;https://www.apachefriends.org/index.html 選擇XAMPP版本&#xff1a; 在XAMPP的下載頁面上&#xff0c;選擇適合Windows的最新穩定版本下載&#xff08;例…

【DeepSeek】本地部署,保姆級教程

deepseek網站鏈接傳送門&#xff1a;DeepSeek 在這里主要介紹DeepSeek的兩種部署方法&#xff0c;一種是調用API&#xff0c;一種是本地部署。 一、API調用 1.進入網址Cherry Studio - 全能的AI助手選擇立即下載 2.安裝時位置建議放在其他盤&#xff0c;不要放c盤 3.進入軟件后…

Python 入門教程(2)搭建環境 | 2.3、VSCode配置Python開發環境

文章目錄 一、VSCode配置Python開發環境1、軟件安裝2、安裝Python插件3、配置Python環境4、包管理5、調試程序 前言 Visual Studio Code&#xff08;簡稱VSCode&#xff09;以其強大的功能和靈活的擴展性&#xff0c;成為了許多開發者的首選。本文將詳細介紹如何在VSCode中配置…

Oracle EBS 12.1和APEX 集成時 Apache的配置代理

在有些場景下&#xff0c;apex的前端服務不是和oracle EBS 應用部署在同一個服務器上或者要求apex和訪問地址和EBS公用同一個域名同一個端口&#xff0c;那么怎么才能做到用EBS 的域名和端口來實現對apex的訪問呢 通過配置代理規則解決&#xff0c;以Oracle EBS 12.1.3 為例&am…

【第二節】C++設計模式(創建型模式)-抽象工廠模式

目錄 引言 一、抽象工廠模式概述 二、抽象工廠模式的應用 三、抽象工廠模式的適用場景 四、抽象工廠模式的優缺點 五、總結 引言 抽象工廠設計模式是一種創建型設計模式&#xff0c;旨在解決一系列相互依賴對象的創建問題。它與工廠方法模式密切相關&#xff0c;但在應用…

ubuntu20.04重啟后不顯示共享文件夾

ubuntu20.04重啟后不顯示共享文件夾 主要參見這兩篇博客 Ubuntu重啟后不顯示共享文件夾_ubuntu 20.04 共享目錄無法使用-CSDN博客 ubuntu22.04 配置共享文件夾 找不到/mnt/hgfs_ubuntu安裝tools 后mnt文件夾在哪-CSDN博客 重啟Ubuntu20.04后&#xff0c;發現共享文件夾進不去…

halcon機器視覺深度學習對象檢測,物體檢測

目錄 效果圖操作步驟軟件版本halcon參考代碼本地函數 get_distinct_colors()本地函數 make_neighboring_colors_distinguishable() 效果圖 操作步驟 首先要在Deep Learning Tool工具里面把圖片打上標注文本&#xff0c; 然后訓練模型&#xff0c;導出模型文件 這個是模型 mod…

9.PG數據庫層權限管理(pg系列課程)第2遍

一、PostgreSQL數據庫屬主 Postgres中的數據庫屬主屬于創建者&#xff0c;只要有createdb的權限就可以創建數據庫&#xff0c;數據庫屬主不一定擁有存放在該數據庫中其它用戶創建的對象的訪問權限。數據庫在創建后&#xff0c;允許public角色連接&#xff0c;即允許任何人連接…

2.19學習(php文件后綴)

misc buu-后門查殺 下載附件&#xff0c;我們用火絨安全掃一下然后點擊詳情進入該文件所在文件夾&#xff0c;再用記事本打開該文件&#xff0c;搜索flag無果&#xff0c;再試試pass&#xff08;由題目中的密碼聯系到pass&#xff0c;password&#xff0c;key等&#xff09;&a…

PMBOK第7版整體架構全面詳解

1. 引言 7月1日對于項目管理從業者和研究者而言&#xff0c;是個非凡意義的一個時間&#xff0c;這一天&#xff0c;翹首以待的《 項 目管理知識體系指南 》&#xff08;PMBOK&#xff09;第七版終于發布了。 總體而言&#xff0c;PMBOK第七版集百家之所長&#xff0c;成一…

C++:類與對象,定義類和構造函數

#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; //如何讓定義一個類 // 封裝 // 1、將數據和方法定義到一起。 // 2、把想給你看的數據給你看&#xff0c;不想給你看的封裝起來。 通過訪問限定符來實現 class Stack { public: //1.成…

nginx 部署前端vue項目

?? 主頁&#xff1a; ?? 感謝各位大佬 點贊?? 收藏 留言?? 加關注! ?? 收錄于專欄&#xff1a;前端工程師 文章目錄 一、??什么是nginx&#xff1f;二、??nginx 部署前端vue項目步驟 2.1 ??安裝nginx 2.1.1 ??windows環境安裝2.1.2 ??linux環境安裝 2.2 …

藍橋杯備考策略

備賽策略 (1-2周):基礎算法數據結構 (3-5周):動態規劃/貪心圖論 (6-8周):全真模擬查漏補缺 階段1:基礎鞏固(第1-2周) **目標:**掌握基礎數據結構和必考算法&#xff0c;熟悉藍橋杯題型。 學習內容: 數據結構:數組、字符串、棧、隊列、哈希表、二叉樹(遍歷與基本操作)。 基礎…

tmux和vim的基本操作

Tmux Tmux 的核心功能 多窗口和多面板&#xff1a; 在一個終端中創建多個窗口&#xff08;Windows&#xff09;&#xff0c;每個窗口可以運行不同的任務。 在每個窗口中&#xff0c;可以進一步分割成多個面板&#xff08;Panes&#xff09;&#xff0c;實現分屏操作。 會話…

Lineageos 22.1(Android 15) 開機向導制作

一、前言 開機向導原理其實就是將特定的category的Activity加入ComponentResolver&#xff0c;如下 <category android:name"android.intent.category.SETUP_WIZARD"/>然后我們開機啟動的時候&#xff0c;FallbackHome結束&#xff0c;然后啟動Launcher的時候…