全新升級的AOP框架Dora.Interception[5]: 實現任意的攔截器注冊方式

Dora.Interception提供了兩種攔截器注冊方式,一種是利用標注在目標類型、屬性和方法上的InterceptorAttribute特性,另一種采用基于目標方法或者屬性的調用表達式。通過提供的擴展點,我們可以任何我們希望的攔截器注冊方式。

目錄
一、IInterceptorProvider
二、InterceptorProviderBase
三、實現一種“萬能”的攔截器注冊方式
四、ConditionalInterceptorProvider

一、IInterceptorProvider

攔截器最終需要應用到某個具體的目標方法上,所以攔截器的注冊就是如何建立攔截器與目標方法之間的映射關系,Dora.Interception將這一功能體現在如下所示的IInterceptorProvider接口上。顧名思義,IInterceptorProvider旨在解決為某個類型的某個方法提供攔截器列表的問題,這一個功能體現在GetInterceptors方法上。如下面的代碼片段所示,該方法返回一組Sortable<InvokeDelegate>對象,InvokeDelegate代表攔截器本身,Sortable<InvokeDelegate>對象在此基礎上添加了必要排序元素。

public?interface?IInterceptorProvider
{bool?CanIntercept(Type?targetType,?MethodInfo?method,?out?bool?suppressed);IEnumerable<Sortable<InvokeDelegate>>?GetInterceptors(Type?targetType,?MethodInfo?method);void?Validate(Type?targetType,?Action<MethodInfo>?methodValidator,?Action<PropertyInfo>?propertyValidator)?{}
}public?sealed?class?Sortable<T>
{public?int?Order?{?get;?}public?T?Value?{?get;?set;?}public?Sortable(int?order,?T?value){Order?=?order;Value?=?value;}
}

除了GetInterceptors方法,IInterceptorProvider接口還定義了額外兩個方法,CanIntercept方法用來判斷指定的方式是否需要被攔截,代碼生成器會利用這個方法決定如果生成最終可供攔截的代理類。另一個Validate方法用來驗證針對指定類型的攔截器注冊方式是否合法,即攔截器是否應用到一些根本無法被攔截的方法或者屬性上,具體的檢驗邏輯由方法提供的兩個委托來完成。

二、InterceptorProviderBase

我們自定義的IInterceptorProvider實現類型一般派生于如下這個抽象基類InterceptorProviderBase,后者在接口的基礎上提供了一個IConventionalInterceptorFactory接口類型的InterceptorFactory屬性。顧名思義,IConventionalInterceptorFactory對象幫助我們按照約定定義的攔截器類型或者其實例轉換成標準的攔截器表現形式,即InvokeDelegate委托。

public?abstract?class?InterceptorProviderBase?:?IInterceptorProvider
{public?IConventionalInterceptorFactory?InterceptorFactory?{?get;?}??protected?InterceptorProviderBase(IConventionalInterceptorFactory?interceptorFactory)?;public?abstract?bool?CanIntercept(Type?targetType,?MethodInfo?method,?out?bool?suppressed);public?abstract?IEnumerable<Sortable<InvokeDelegate>>?GetInterceptors(Type?targetType,?MethodInfo?method);
}public?interface?IConventionalInterceptorFactory
{InvokeDelegate?CreateInterceptor(Type?interceptorType,?params?object[]?arguments);InvokeDelegate?CreateInterceptor(object?interceptor);
}

三、實現一種“萬能”的攔截器注冊方式

接下來我們通過自定義的IInterceptorProvider類型實現一種“萬能”的攔截器注冊方式——根據指定的條件表達式將指定的攔截器關聯到目標方法上。在提供具體實現之前,我們先來體驗一下由它達成的編程模型。

public?class?FoobarInterceptor
{public?ValueTask?InvokeAsync(InvocationContext?invocationContext){var?method?=?invocationContext.MethodInfo;Console.WriteLine($"{method.DeclaringType!.Name}.{method.Name}?is?intercepted.");return?invocationContext.ProceedAsync();}
}public?class?Foobar
{public?virtual?void?M()?{?}public?virtual?object??P?{?get;?set;?}}

我們依然以上面這個簡單的攔截器類型FoobarInterceptor為例,現在我們需要將它應用到Foobar類型的M和P屬性的Set方法上,針對FoobarInterceptor的注冊就可以按照如下方式來完成。如代碼片段所示,我們在調用InterceptionBuilder的RegisterInterceptors擴展方法中提供了一個Action<ConditionalInterceptorProviderOptions>委托,并利用它添加了針對FoobarInterceptor與兩個Func<Type, MethodInfo, bool>委托之間的關系,后者用來匹配目標方法(含屬性方法)。

var?foobar=?new?ServiceCollection().AddSingleton<Foobar>().BuildInterceptableServiceProvider(interception?=>?interception.RegisterInterceptors(RegisterInterceptors)).GetRequiredService<Foobar>();foobar.M();
_?=?foobar.P;
foobar.P?=?null;
Console.ReadLine();static?void?RegisterInterceptors(ConditionalInterceptorProviderOptions?options)
{options.For<FoobarInterceptor>().To(1,?(type,?method)?=>?type?==?typeof(Foobar)?&&?method.Name?==?"M").To(1,?(type,?method)??=>?type?==?typeof(Foobar)?&&?method.IsSpecialName?&&?method.Name?==?"set_P");
}

程序運行后會在控制臺輸出如下的結果,可以看出FoobarInterceptor攔截確實只應用到M和P屬性的Set方法上,屬性的Get方法并未被攔截。

d1a6978e717abf250ec1deb1ae622653.png

四、ConditionalInterceptorProvider

上述這種針對匹配條件的“萬能”注冊方式是通過如下這個ConditionalInterceptorProvider類型實現的。ConditionalInterceptorProviderOptions類型定義了對應的配置選項,其核心就是一組ConditionalInterceptorRegistration對象的集合,而每一個ConditionalInterceptorRegistration對象是一個表示匹配條件的Func<Type, MethodInfo, bool>委托與攔截器工廠的Func<IConventionalInterceptorFactory, Sortable<InvokeDelegate>>委托之間的映射關系,后者利用指定的IConventionalInterceptorFactory來創建一個對應的Sortable<InvokeDelegate>對象。

public?class?ConditionalInterceptorProvider?:?InterceptorProviderBase
{private?readonly?ConditionalInterceptorProviderOptions?_options;public?ConditionalInterceptorProvider(IConventionalInterceptorFactory?interceptorFactory,?IOptions<ConditionalInterceptorProviderOptions>?optionsAccessor)?:?base(interceptorFactory)=>?_options?=?optionsAccessor.Value;public?override?bool?CanIntercept(Type?targetType,?MethodInfo?method,?out?bool?suppressed){suppressed?=?false;return?_options.Registrations.Any(it?=>?it.Condition(targetType,?method));}public?override?IEnumerable<Sortable<InvokeDelegate>>?GetInterceptors(Type?targetType,?MethodInfo?method)=>?_options.Registrations.Where(it?=>?it.Condition(targetType,?method)).Select(it?=>?it.Factory(InterceptorFactory)).ToList();
}public?class?ConditionalInterceptorProviderOptions
{public?IList<ConditionalInterceptorRegistration>?Registrations?{?get;?}?=?new?List<ConditionalInterceptorRegistration>();public?Registry<TInterceptor>?For<TInterceptor>(params?object[]?arguments)=>?new(factory?=>?factory.CreateInterceptor(typeof(TInterceptor),?arguments),?this);
}public?class?Registry<TInterceptor>
{private?readonly?Func<IConventionalInterceptorFactory,?InvokeDelegate>?_factory;private?readonly?ConditionalInterceptorProviderOptions?_options;public?Registry(Func<IConventionalInterceptorFactory,?InvokeDelegate>?factory,?ConditionalInterceptorProviderOptions?options){_factory?=?factory;_options?=?options;}public?Registry<TInterceptor>?To(int?order,?Func<Type,?MethodInfo,?bool>?condition){var?entry?=?new?ConditionalInterceptorRegistration(condition,?factory=>new?Sortable<InvokeDelegate>(order,?_factory(factory)));_options.Registrations.Add(entry);return?this;}
}public?class?ConditionalInterceptorRegistration
{public?Func<Type,?MethodInfo,?bool>?Condition?{?get;?}public?Func<IConventionalInterceptorFactory,?Sortable<InvokeDelegate>>?Factory?{?get;?}public?ConditionalInterceptorRegistration(Func<Type,?MethodInfo,?bool>?condition,?Func<IConventionalInterceptorFactory,?Sortable<InvokeDelegate>>?factory){Condition?=?condition;Factory?=?factory;}
}

這一組映射關系利用ConditionalInterceptorProviderOptions的For<TInterceptor>方法進行添加,該方法返回一個Registry<TInterceptor>對象,后者提供的To方法指定了作為匹配條件的Func<Type, MethodInfo, bool>委托和決定攔截器執行順序的Order值。ConditionalInterceptorProvider利用構造函數注入的IOptions<ConditionalInterceptorProviderOptions>得到這組映射關系,CanIntercept方法利用這組關系的匹配條件確定指定的方法是否應該被攔截,另一個GetInterceptors方法則利用匹配的工廠來創建返回的這組Sortable<InvokeDelegate>對象。

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

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

相關文章

SCAU 算法課的題

8594 有重復元素的排列問題&#xff08;優先做&#xff09; 時間限制:1000MS 內存限制:1000K提交次數:1610 通過次數:656 題型: 編程題 語言: G;GCC;VC Description 設集合R{r1,r2,...,rn}是要進行排列的n個元素&#xff0c;其中r1,r2,...,rn可能相同。 試著設計一個算法&am…

react 數組新增_React 新特性 Hooks 講解及實例(二)

本文是 React 新特性系列的第二篇&#xff0c;第一篇請點擊這里&#xff1a;React 新特性講解及實例什么是 HooksHook 是 React 16.8 的新增特性。它可以讓你在不編寫 類組件 的情況下使用 state以及其他的 React 特性。類組件的不足狀態邏輯復用難缺少復用機制渲染屬性和高階組…

智課雅思詞匯---二十二、-al即是名詞性后綴又是形容詞后綴

智課雅思詞匯---二十二、-al即是名詞性后綴又是形容詞后綴 一、總結 一句話總結&#xff1a; 后綴&#xff1a;-al ②[名詞后綴] 1、構成抽象名詞&#xff0c;表示行為、狀況、事情 refusal 拒絕 proposal 提議 withdrawal 撤退 1、名詞性后綴acy是什么意思&#xff1f; 后綴&a…

javascript事件處理程序

javascript 事件處理程序 1、普通事件處理程序 <input type"button" value"click me" οnclick"showMessage()" /> function showMessage(){alert("clicked");} 2、DOMO 級事件處理程序 <span style"white-space:pre&…

eclipse新發現功能之dos和terminal(ssh連接)

dos功能&#xff1a; window——》show view——》other——》remote systems&#xff0c;選擇remote shell&#xff0c;選擇確定或者雙擊&#xff0c;打開了一個新工具窗口。點擊remote shell窗口最右上角的小三角&#xff0c;在launch子菜單中選擇local&#xff0c;點擊即可。…

7天學會python_7天學會Python最佳可視化工具Seaborn(五):結構化展示多維數據

當探索具有中等數量(不多不少的意思……)維度的數據集時&#xff0c;一個很好的方式是基于不同的子數據集構建不同的實例&#xff0c;并將它們以網格的方式組織在一張圖之中。這種技術有時被稱為“lattice”或“trellis”(大概是格子圖、網格圖)&#xff0c;這跟“small multip…

面對峰值響應沖擊,解決高并發的三大策略

2019獨角獸企業重金招聘Python工程師標準>>> 當前在互聯網的大潮下&#xff0c;眾所周知淘寶、京東這些交易系統每天產生的數據量都是海量的&#xff0c;每天的交易并發也是驚人的&#xff0c;尤其是“雙11”、“6.18”這些活動&#xff0c;對系統的峰值響應提出了非…

.NET 采用 SkiaSharp 生成二維碼和圖形驗證碼及圖片進行指定區域截取方法實現

在最新版的 .NET 平臺中&#xff0c;微軟在逐步放棄 System.Drawing.Imaging &#xff0c;給出的理由如下&#xff1a;System.Drawing命名空間對某些操作系統和應用程序類型有一些限制。在Windows&#xff0c; System.Drawing 依賴于GDI操作系統附帶的本機庫。 某些Windows SKU…

Linux運維人員必會開源運維工具體系

新手必會用深&#xff08;8-15k&#xff09;標記&#xff0c;老鳥必會深淺藍色(15-25K)標記操作系統&#xff1a;Centos,Ubuntu,Redhat,suse,Freebsd網站服務&#xff1a;nginx,apache,lighttpd,php,tomcat,resin數據 庫&#xff1a;MySQL,MariaDB,PostgreSQLDB中間件&#x…

unity讀取Text

sing UnityEngine;using System.Collections;using System.IO; //需要導入System.IO&#xff0c;主要使用它的File類public class TextTest : MonoBehaviour { private string Mytxt; //用來存放文本內容 void Start() { Mytxt ReadFile("C:\\Users\\Admin\\Desktop\\測試…

hibernate mysql 主從_MYSQL主從復制和寫分離

基礎篇https://edu.51cto.com/course/19845.htmlhttps://edu.51cto.com/course/19845.htmlhttps://edu.51cto.com/course/19841.htmlhttps://edu.51cto.com/course/21197.htmlhttps://edu.51cto.com/course/19886.htmlhttps://edu.51cto.com/course/19887.htmlhttps://edu.51ct…

深入剖析Redis系列(五) - Redis數據結構之字符串

前言 字符串類型 是 Redis 最基礎的數據結構。字符串類型 的值實際可以是 字符串&#xff08;簡單 和 復雜 的字符串&#xff0c;例如 JSON、XML&#xff09;、數字&#xff08;整數、浮點數&#xff09;&#xff0c;甚至是 二進制&#xff08;圖片、音頻、視頻&#xff09;&am…

全新升級的AOP框架Dora.Interception[6]: 框架設計和實現原理

本系列前面的五篇文章主要介紹Dora.Interception的編程模式以及對它的擴展定制&#xff0c;現在我們來聊聊它的設計和實現原理。目錄一、調用鏈抽象二、基于約定的攔截器定義三、基于調用上下文的依賴注入容器四、攔截器的提供五、調用鏈的構建六、方法攔截的實現原理七、依賴注…

activemq 安全連接

一、定義用戶組1.1 simpleAuthenticationPlugin通過在activemq.xml中配置用戶組<plugins> <simpleAuthenticationPlugin> <users> <authenticationUser username"admin" password"password" groups"admins,publishers,consumer…

React Native在Android當中實踐(五)——常見問題

React Native在Android當中實踐&#xff08;一&#xff09;——背景介紹 React Native在Android當中實踐&#xff08;二&#xff09;——搭建開發環境 React Native在Android當中實踐&#xff08;三&#xff09;——集成到Android項目當中 React Native在Android當中實踐&#…

完成登錄與注冊頁面的前端

完成登錄與注冊頁面的HTMLCSSJS&#xff0c;其中的輸入項檢查包括&#xff1a; 用戶名6-12位 首字母不能是數字 只能包含字母和數字 密碼6-12位 注冊頁兩次密碼是否一致 JS&#xff1a; function fnLogin() {var uSer document.getElementById("user");var pAss do…

mysql505復位密碼_mysql5 如何復位根用戶密碼[官方文檔]

如何復位根用戶密碼如果你從未為MySQL設置根用戶密碼&#xff0c;服務器在以根用戶身份進行連接時不需要密碼。但是&#xff0c;建議你為每個賬戶設置密碼如果你以前設置了根用戶密碼&#xff0c;但卻忘記了該密碼&#xff0c;可設置新的密碼。下述步驟是針對Windows平臺的。在…

WPF效果第二百零一篇之實現合并單元格

早一段時間又一次出差青海省西寧市;回來又是總結又是各種瑣事,也沒顧得上去分享點東西;大周末的就在家分享一下,這二天再次基于ListBox實現的合并單元格的效果:1、ListBox嵌套ListBox的前臺布局:<ListBox ItemsSource"{Binding LCPListData}" x:Name"Manufac…

轉載 maven 詳解 http://www.cnblogs.com/binyue/p/4729134.html

--聲明規范 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!--聲…

ASP.NET Core中使用EasyCaching作為緩存抽象層

簡介做后端開發&#xff0c;緩存應該是天天在用&#xff0c;很多時候我們的做法是寫個幫助類&#xff0c;然后用到的時候調用一下。這種只適合簡單層次的應用&#xff1b;一旦涉及到接口實現調整之類的&#xff0c;這種強耦合的做法很不合適。有些其他的功能又要去重復造輪子。…