手寫MyBatis第47彈:Interceptor接口設計與Invocation上下文傳遞機制--MyBatis動態代理生成與方法攔截的精妙實現

🥂(?′?`?)您的點贊👍?評論📝?收藏?是作者創作的最大動力🤞

💖📕🎉🔥 支持我:點贊👍+收藏??+留言📝歡迎留言討論

🔥🔥🔥(源碼 + 調試運行 + 問題答疑)

🔥🔥🔥 ?有興趣可以聯系我。

我們常常在當下感到時間慢,覺得未來遙遠,但一旦回頭看,時間已經悄然流逝。對于未來,盡管如此,也應該保持一種從容的態度,相信未來仍有許多可能性等待著我們。?

目錄

一、Interceptor接口:插件系統的契約

二、Invocation對象:調用上下文的完整封裝

三、proceed()方法:鏈式調用的引擎

四、Plugin.wrap方法:代理生成的工廠

五、插件如何修改參數和返回值

六、總結:鏈式調用的設計哲學


  1. MyBatis插件鏈式調用深度解析:Interceptor接口設計與Invocation上下文傳遞機制

  2. 手寫MyBatis(八):插件鏈式調用與Invocation.proceed的遞歸魔法

  3. 從攔截到修改:MyBatis插件如何操縱方法參數與返回值的核心技術

  4. Plugin.wrap方法揭秘:MyBatis動態代理生成與方法攔截的精妙實現


在上一篇文章中,我們探討了MyBatis多插件管理的責任鏈模式。今天,我們將深入這個鏈條的內部,解析鏈式調用的實現細節,特別是Interceptor接口的設計、Invocation對象的作用以及proceed()方法如何實現遞歸調用。這些看似簡單的組件背后,隱藏著MyBatis插件系統最精妙的設計思想。

一、Interceptor接口:插件系統的契約

Interceptor接口是MyBatis插件系統的核心契約,它定義了插件必須實現的三個關鍵行為:

?public interface Interceptor {// 核心攔截方法:包含插件的主要邏輯Object intercept(Invocation invocation) throws Throwable;// 默認方法:用于包裝目標對象生成代理default Object plugin(Object target) {return Plugin.wrap(target, this);}// 設置插件屬性(可選)default void setProperties(Properties properties) {// 默認空實現}}

這個接口設計的精妙之處在于:

  1. intercept方法:這是插件的核心,包含了插件的主要業務邏輯。它接收一個Invocation參數,這個參數封裝了完整的調用上下文。

  2. plugin默認方法:這是一個非常巧妙的設計。通過提供默認實現,MyBatis讓插件開發者無需關心復雜的代理生成邏輯,只需要專注于業務邏輯的實現。這個方法確保了所有插件都使用統一的代理生成機制。

  3. setProperties方法:允許插件接收外部配置參數,增強了插件的靈活性。

二、Invocation對象:調用上下文的完整封裝

Invocation對象是插件鏈式調用的核心載體,它封裝了一次方法調用的所有必要信息:

?public class Invocation {private final Object target; ? ? // 被代理的原始對象private final Method method; ? ? // 被攔截的方法private final Object[] args; ? ? // 方法參數public Invocation(Object target, Method method, Object[] args) {this.target = target;this.method = method;this.args = args;}// 關鍵方法:繼續執行調用鏈public Object proceed() throws InvocationTargetException, IllegalAccessException {return method.invoke(target, args);}// Getter方法public Object getTarget() { return target; }public Method getMethod() { return method; }public Object[] getArgs() { return args; }// 設置參數(用于修改參數)public void setArgs(Object[] args) { this.args = args; }}

Invocation的設計體現了"信息專家"模式——它將一次方法調用的所有相關信息集中管理,為插件提供了完整的操作上下文。

三、proceed()方法:鏈式調用的引擎

proceed()方法是整個插件鏈式調用機制的核心。它的作用看似簡單——調用目標方法,但在責任鏈模式中,它的行為實際上要復雜得多:

從圖中可以看出,proceed()方法實際上觸發了一個遞歸的調用過程:

  1. 最外層插件首先執行前置處理邏輯

  2. 調用proceed(),該方法實際上會調用下一個插件intercept方法

  3. 這個過程遞歸進行,直到最后一個插件調用proceed()

  4. 最后一個proceed()調用原始目標方法

  5. 然后調用棧逐層返回,每個插件執行后置處理邏輯

  6. 最終返回到最外層插件,完成整個調用鏈

這種設計的美妙之處在于:每個插件都無需知道整個調用鏈的結構,它只需要調用proceed()并將處理權交給鏈條的下一個環節即可

四、Plugin.wrap方法:代理生成的工廠

Plugin.wrap()是插件機制中的另一個關鍵組件,它負責創建動態代理對象:

?public class Plugin implements InvocationHandler {private final Object target; ? ? ? ? ? ? ? ? // 原始對象private final Interceptor interceptor; ? ? ? // 插件實例private final Map<Class<?>, Set<Method>> signatureMap; // 方法簽名映射public static Object wrap(Object target, Interceptor interceptor) {// 獲取插件聲明的攔截點Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);Class<?> type = target.getClass();// 獲取目標對象實現的所有需要被攔截的接口Class<?>[] interfaces = getAllInterfaces(type, signatureMap);if (interfaces.length > 0) {// 創建動態代理return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 檢查當前方法是否需要被攔截Set<Method> methods = signatureMap.get(method.getDeclaringClass());if (methods != null && methods.contains(method)) {// 如果需要攔截,調用插件的intercept方法return interceptor.intercept(new Invocation(target, method, args));}// 否則直接調用原始方法return method.invoke(target, args);}}

Plugin.wrap()的智能之處在于它只會為那些實現了插件聲明要攔截的接口的對象創建代理,避免了不必要的性能開銷。

五、插件如何修改參數和返回值

基于上述架構,插件可以很容易地修改方法參數和返回值:

1. 修改方法參數:

?@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 獲取原始參數Object[] args = invocation.getArgs();// 修改參數(例如加密參數)if (args[0] instanceof String) {args[0] = encrypt((String) args[0]);}// 重要:將修改后的參數設置回Invocationinvocation.setArgs(args);// 繼續執行調用鏈return invocation.proceed();}

2. 修改返回值:

?@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 執行原有邏輯并獲取返回值Object result = invocation.proceed();// 修改返回值(例如解密結果)if (result instanceof String) {result = decrypt((String) result);}return result;}

3. 完全替換方法邏輯:

?@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 不調用proceed,完全由插件實現方法邏輯if (shouldReplaceLogic(invocation)) {return customLogic(invocation);}// 否則正常執行原有邏輯return invocation.proceed();}
六、總結:鏈式調用的設計哲學

MyBatis插件鏈式調用機制的設計體現了多個重要的軟件設計原則:

  1. 開閉原則:通過插件機制,可以在不修改框架源碼的情況下擴展功能。

  2. 單一職責原則:每個插件只關注一個特定的功能點。

  3. 依賴倒置原則:插件依賴于抽象的Interceptor接口,而不是具體的實現。

  4. 信息專家模式Invocation對象集中管理了調用相關的所有信息。

這種設計不僅使得MyBatis插件系統極其強大和靈活,也為我們提供了如何設計可擴展架構的寶貴范例。無論是開發框架還是業務系統,這種責任鏈模式和鏈式調用的思想都值得深入學習和應用。


💖學習知識需費心,
📕整理歸納更費神。
🎉源碼免費人人喜,
🔥碼農福利等你領!

💖常來我家多看看,
📕我是程序員扣棣,
🎉感謝支持常陪伴,
🔥點贊關注別忘記!

💖山高路遠坑又深,
📕大軍縱橫任馳奔,
🎉誰敢橫刀立馬行?
🔥唯有點贊+關注成!

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

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

相關文章

自動駕駛中的傳感器技術37——Lidar(12)

這里對當前Lidar中的一些常見問題進行專項論述。首先以禾賽Lidar為例&#xff0c;列出相關參數&#xff0c;以備論述。 圖1 禾賽AT128參數圖2 禾賽AT360參數圖3 禾賽AT1440參數圖4 禾賽AT128可靠性驗證項圖5 禾賽AT128產品證書1、Lidar的線束是什么&#xff0c;由什么決定&…

Meteor主題友鏈頁面自研

發布于&#xff1a;Eucalyptus-Blog Meteor主題雖然設計簡約現代&#xff0c;但由于缺乏原生的友情鏈接管理功能&#xff0c;許多博主只能將友情鏈接勉強添加在網站底部&#xff0c;這不僅影響頁面美觀&#xff0c;也不便于訪客查找和互動&#xff1b;為了解決這一痛點&#xf…

QT控件QPlainTextEdit、QTextEdit與QTextBrowser的區別

一.主要功能對比二.關鍵功能差異1.文本類型支持QPlainTextEdit&#xff1a;僅支持純文本&#xff08;Plain Text&#xff09;&#xff0c;不處理任何格式&#xff08;如字體、顏色、鏈接、圖片等&#xff09;。文本以原始字符形式存儲&#xff0c;適合處理日志、代碼、配置文件…

【思考】WSL是什么

WSL WSL是什么呢&#xff1f; WSL 是 windows subsystem for linux 的簡寫&#xff0c;指的是 windows10 的一個子系統&#xff0c;這個子系統的作用是在 windows 下運行 linux 操作系統。 有了WSL&#xff0c;就可以在 windows10 中運行linux操作系統了。許多在 linux 種運行的…

基于單片機智能飲水機/智能熱水壺

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目速選一覽表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目功能速覽 概述 基于單片機的智能飲水機系統通過嵌入式技術實現水溫控制、水量監測及用戶交互功能。系統采用STM3…

Unity游戲打包——iOS打包基礎、傳包

本文由 NRatel 歷史筆記整理而來&#xff0c;如有錯誤歡迎指正。 相關參考文檔 Unity文檔 -> 平臺開發 -> IOS https://docs.unity3d.com/cn/2021.3/Manual/iphone.html Unity導出的Xcode 項目的結構 Modifying an Xcode project use Xcode.PBXProject. https://doc…

pyside6小項目:進制轉換器

from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication,QWidgetclass MyWindow(QWidget):def __init__(self):super().__init__()self.ui QUiLoader().load(trans.ui)self.ui.show()#stor data type dictionaryself.lengthVar {米:100, 千米:…

再見 K8s!3款開源的云原生部署工具

前文&#xff0c;和大家分享了云原生中的核心工具 K8s&#xff1a; 關于 K8s&#xff1a;入門&#xff0c;這篇就夠了 K8s是個好東西&#xff0c;就是上手門檻有點高。這不&#xff0c;需求就來了&#xff1f; 有需求&#xff0c;就有工具。 為了解決K8s的配置難題&#xf…

C++ 快速復習指南(上半部分)

1.基礎語法基本結構#include <iostream> 頭名 using namesapce std ; 統一使用命名空間 int main () { 程序執行門戶 主題內容}基本輸出 cout << "string " << endl; // 輸出 string 變量和數據類型 格式int intger 10 ;常量的引入 需要在變量…

ArcGIS Pro 地圖打包與解包

如果需要在ArcGIS Pro 打包某一個地圖文檔&#xff0c;在 菜單欄中 點擊 共享&#xff0c;點擊地圖。彈出 打包地圖 面板&#xff0c;可以打包到Online、打包到地圖包&#xff0c;選擇將包保存到文件&#xff0c;修改項目詳細信息&#xff0c;點擊 包&#xff0c;即可實現打包。…

sunset: twilight靶場

sunset: twilight 來自 <sunset: twilight ~ VulnHub> 1&#xff0c;將兩臺虛擬機網絡連接都改為NAT模式 2&#xff0c;攻擊機上做namp局域網掃描發現靶機 nmap -sn 192.168.23.0/24 那么攻擊機IP為192.168.23.128&#xff0c;靶場IP192.168.23.145 3&#xff0c;對靶機…

【機器學習基礎】無監督學習算法的現代演進:從數據探索到智能系統的自主發現能力

1. 引言:無監督學習在人工智能革命中的核心價值 在人工智能技術飛速發展的今天,無監督學習正在成為推動AI系統實現真正智能的關鍵技術。與需要大量標注數據的監督學習不同,無監督學習能夠從原始數據中自主發現隱藏的模式和結構,這種能力使其在現代AI應用中具有不可替代的價…

PetaLinux的JTAG啟動

csdn–PetaLinux 使用技巧與緩存配置 xilinx官網–PetaLinux 工具文檔參考指南 (ug1144) xilinx官網–設備樹配置文檔 內核官網–設備樹文檔 軟硬件準備 分類項目說明/用途驗證方法示例硬件JTAG 線JTAG 下載、調試—UART 串口線查看 zynq 啟動日志—網口線用于 TFTP 下載—…

單片機中的按鍵防抖

按鈕&#xff08;按鍵&#xff09;抖動是單片機開發中常見的硬件問題&#xff0c;本質是機械觸點接觸瞬間的物理彈跳導致的電信號不穩定。消除抖動&#xff08;防抖&#xff09;是確保按鍵狀態檢測準確的關鍵&#xff0c;下面從原理到實現詳細講解。 一、按鈕抖動的原理&#x…

面經分享--小米Java一面

目錄 1.Kafka和RocketMQ的區別 2.反射的作用 3.類加載的具體過程&#xff0c;雙親委派模型的機制 4.TCP的四次揮手 5.多線程的優勢 6.死鎖產生的原因&#xff0c;怎么解決 7.Java并發的工作原理 8.常用的git命令 9.算法題 1.leetcode 3.無重復字符的最長子串&#xff…

Python在邊緣計算與物聯網中的創新實踐:實時數據處理與設備控制

近年來&#xff0c;Python語言的普及度持續攀升&#xff0c;尤其在人工智能、數據科學等熱門領域備受青睞。然而&#xff0c;一個新興趨勢——邊緣計算與物聯網&#xff08;IoT&#xff09;的結合——正悄然改變技術格局。邊緣計算強調在數據源頭進行實時處理&#xff0c;減少云…

Spring Cloud Gateway 網關(五)

目錄 一 概念引入 二 具體使用 1 首先創建一個網關模塊 2 啟動類 3 配置類 4 對應方法的修改 5 展示借助81端口進行轉發控制 6 斷言規則?編輯 三 過濾器 1 將前置的請求參數給過濾掉&#xff0c;降低繁瑣程度。 2 默認過濾器 3 全局過濾器 4 自定義過濾器工廠 5…

產品經理操作手冊(8)——業務需求文檔(BRD)

一、BRD的定義與價值 **業務需求文檔(BRD)**是產品開發前期的基礎性文檔&#xff0c;它將業務訴求轉化為結構化的產品需求&#xff0c;是連接業務方與交付團隊的橋梁。“BRD不僅是一份文檔&#xff0c;而是一個對齊的過程。”BRD核心價值 統一認知&#xff1a;確保各方對業務目…

Excel表格多級下拉選項,如何制作?

之前分享過如何設置下拉選項&#xff0c;但那只是簡單的一級下拉菜單&#xff0c;今天再給大家分享多級下拉菜單如何制作。也就是根據前面的下拉選項改變后面的選項。 我們現來復習一級下拉菜單&#xff0c;再接著講多級下拉菜單 一級下拉選項 首先我們先將表格內容湊填寫好…

[Sync_ai_vid] 唇形同步評判器 | 圖像與視頻處理器 | GPU測試

第4章&#xff1a;SyncNet唇形同步評判器 在前幾章中&#xff0c;我們了解了唇形同步推理流程如何協調生成唇形同步視頻&#xff0c;以及音頻特征提取器(Whisper)如何為LatentSync UNet提供關鍵音頻線索。 UNet利用這些線索巧妙調整唇部動作。但我們如何判斷UNet的生成效果&a…