全新升級的AOP框架Dora.Interception[匯總,共6篇]
- 2022 年 6 月 30 日
- 筆記
- .NET, .NET Core, [05] 開源框架, AOP, Dependency Injection, Dora, Dora.Interception, Roslyn
多年之前利用IL Emit寫了一個名為Dora.Interception(github地址,覺得不錯不妨給一顆星)的AOP框架。前幾天利用Roslyn的Source Generator對自己為公司寫的一個GraphQL框架進行改造,性能得到顯著的提高,覺得類似的機制同樣可以用在AOP框架上,實驗證明這樣的實現方式不僅僅極大地改善性能(包括執行耗時和GC記憶體分配),而且讓很多的功能特性變得簡單了很多。這並不是說IL Emit性能不好(其實恰好相反),而是因為這樣的實現太複雜,面向IL編程比寫彙編差不多。由於AOP攔截機制涉及的場景很多(比如非同步等待、泛型類型和泛型方法、按地址傳遞參數等等),希望完全利用IL Emit高效地實現所有的功能特性確實很難,但是從C#程式碼的層面去考慮就簡單多了。(拙著《ASP.NET Core 6框架揭秘》6折優惠,首印送簽名專屬書籤)
[1]編程體驗
除了性能的提升和保持低侵入性,Dora.Interception在編程方式上於其他所有的AOP框架都不太相同。在攔截器的定義上,我們並沒有提供介面和基類來約束攔截方法的實現,而是採用「基於約定」的編程模式將攔截器定義成一個普通的類,攔截方法上可以任意注入依賴的對象。在如何應用定義的攔截器方面,我們提供了常見的「特性標註」的編程方式將攔截器與目標類型、方法和屬性建立關聯,我們還提供了一種基於「表達式」的攔截器應用方式。Dora.Interception主張將攔截器「精準」地應用到具體的目標方法上,所以提供的這兩種方式針對攔截器的應用都是很「明確的」。如果希望更加靈活的攔截器應用方式,通過提供的擴展可以自由發揮。本章通過一個簡單實例來演示一下Dora.Interception如何使用。閱讀更多…
[2]基於約定的攔截器定義方式
Dora.Interception有別於其他AOP框架的最大的一個特點就是採用針對「約定」的攔截器定義方式。如果我們為攔截器定義了一個介面或者基類,那麼攔截方法將失去任意註冊依賴服務的靈活性。除此之外,由於我們採用了動態程式碼生成的機制,我們可以針對每一個目標方法生成對應的方法調用上下文,所以定義在攔截上下文上針對參數和返回值的提取和設置都是泛型方法,這樣可以避免無謂的裝箱和拆箱操作,進而將引入攔截帶來的性能影響降到最低。閱讀更多…
[3]基於特性標註的攔截器註冊方式
在Dora.Interception中按照約定方式定義的攔截器可以採用多種方式註冊到目標方法上。本篇文章介紹最常用的基於「特性標註」的攔截器註冊方式,下一篇會介紹另一種基於(Lambda)表達式的註冊方式。如果原生定義的這兩種註冊方式不能滿足要求,利用框架提供的擴展,我們可以完成任何你想要的攔截器註冊手段。閱讀更多…
[4]基於Lambda表達式的攔截器註冊
基於特性標註的攔截器註冊方式僅限於將攔截器應用到自己定義的類型上,對於第三方提供的類型就無能為力了。對於Dora.Interception來說,攔截器註冊本質上建立攔截器與一個或者多個目標方法之間的映射,所以最笨的方式就是利用反射的方式得到表示目標方法的MethodInfo對象,並將它與對應的攔截器關聯在一起。這種方式雖然能夠解決問題,但是編程體驗很差。本篇介紹的基於表達式的攔截器註冊方式利用針對目標方法或者屬性的調用表達式,以一種強類型的方式獲取到目標方法,極大地改善了編程體驗。閱讀更多…
[5]實現任意的攔截器註冊方式
Dora.Interception提供了兩種攔截器註冊方式,一種是利用標註在目標類型、屬性和方法上的InterceptorAttribute特性,另一種採用基於目標方法或者屬性的調用表達式。通過提供的擴展點,我們可以任何我們希望的攔截器註冊方式。閱讀更多…
[6]框架設計和實現原理
從設計模式來看,Dora.Interception採用了「職責鏈」模式。我們將應用到同一個方法的多個攔截器以及針對目標方法的調用構建成如下所示的「調用鏈」。調用鏈在執行過程中共享同一個「調用上下文」,後者提供當前調用的上下文資訊,比如目標對象、調用方法、輸出參數和返回值等。每個攔截器不僅可以利用這些上下文資訊執行對應的操作,還可以直接利用此上下文修改參數和返回值,並且自行決定是否繼續執行後續調用。閱讀更多…