全新升級的AOP框架Dora.Interception[3]: 基于特性標注的攔截器注冊方式

在Dora.Interception中按照約定方式定義的攔截器可以采用多種方式注冊到目標方法上。本篇文章介紹最常用的基于“特性標注”的攔截器注冊方式,下一篇會介紹另一種基于(Lambda)表達式的注冊方式:全新升級的AOP框架Dora.Interception[4]: 基于表達式的攔截器注冊。

目錄
一、InterceptorAttribute 特性
二、指定構造攔截器的參數列表
三、將攔截器類型定義成特性
四、合法性檢驗
五、針對類型、屬性的標注
六、攔截的屏蔽

一、InterceptorAttribute 特性

攔截器類型可以利用如下這個InterceptorAttribute特性應用到標注的類型、屬性和方法上。除了通過Interceptor屬性指定攔截器類型之外,我們還可以利用Order屬性控制攔截器的執行順序,該屬性默認值為0。該特性的Arguments用來提供構造攔截器對象的參數。

[AttributeUsage(AttributeTargets.Class?|?AttributeTargets.Method?|?AttributeTargets.Property,?AllowMultiple?=?true,?Inherited?=?false)]
public?class?InterceptorAttribute?:?Attribute
{public?Type?Interceptor?{?get;?}public?object[]?Arguments?{?get;?}public?int?Order?{?get;?set;?}public?InterceptorAttribute(params?object[]?arguments)?:public?InterceptorAttribute(Type??interceptor,?params?object[]?arguments);
}

二、指定構造攔截器的參數列表

攔截器對象是通過依賴注入容器提供的,容器能夠自動提供注入到構造函數中對象。如果構造函數包含額外的參數,對應的參數值就需要利用InterceptorAttribute 特性的Arguments屬性來提供,此屬性由構造函數的arguments參數提供。

public?class?FoobarInterceptor
{public?string?Name?{?get;??}public?FoobarInterceptor(string?name,?IFoobar?foobar){Name?=?name;Debug.Assert(foobar?is?not?null);}public?ValueTask?InvokeAsync(InvocationContext?invocationContext){Console.WriteLine($"FoobarInterceptor?'{Name}'?is?invoked.");return?invocationContext.ProceedAsync();}
}public?interface?IFoobar?{?}
public?class?Foobar?:?IFoobar?{?}

對于如上這個攔截器類型FoobarInterceptor,其構造函數定義了一個字符串的參數name用來指定攔截器的名稱,當我利用InterceptorAttribute 特性將此攔截器應用到Invoker類型的Invoke1和Invoke2方法上是,就需要按照如下的方式指定具體的名稱(Interceptor1和Interceptor2)。

public?class?Invoker
{[FoobarInterceptor("Interceptor1")]public?virtual?void?Invoke1()?=>?Console.WriteLine("Invoker.Invoke1()");[FoobarInterceptor("Interceptor2")]public?virtual?void?Invoke2()?=>?Console.WriteLine("Invoker.Invoke2()");
}

我們按照如下的方式調用Invoker對象的Invoke1和Invoke2方法。

var?invoker?=?new?ServiceCollection().AddSingleton<Invoker>().AddSingleton<IFoobar,?Foobar>().BuildInterceptableServiceProvider().GetRequiredService<Invoker>();invoker.Invoke1();
invoker.Invoke2();

程序執行后,攔截器會以如下的形式將自身的名稱輸出到控制臺上(源代碼)。

ab261cb20808281b74565b8807b2b29b.png

三、將攔截器類型定義成特性

其實我們可以讓定義的攔截器類型派生于InterceptorAttribute 特性,這樣就可以直接將它標注到目標類型、屬性和方法上。比如上面這個FoobarInterceptor類型可以改寫成如下的形式。

public?class?FoobarInterceptorAttribute:?InterceptorAttribute
{public?string?Name?{?get;??}public?FoobarInterceptorAttribute(string?name)?=>?Name?=?name;public?ValueTask?InvokeAsync(InvocationContext?invocationContext){Console.WriteLine($"FoobarInterceptor?'{Name}'?is?invoked.");return?invocationContext.ProceedAsync();}
}

那么它就可以按照如下的方式標注到Invoker類型的兩個方法上(源代碼)。

public?class?Invoker
{[FoobarInterceptor("Interceptor1")]public?virtual?void?Invoke1()?=>?Console.WriteLine("Invoker.Invoke1()");[FoobarInterceptor("Interceptor2")]public?virtual?void?Invoke2()?=>?Console.WriteLine("Invoker.Invoke2()");
}

四、合法性檢驗

只有接口方法和虛方法才能被攔截,Dora.Interception針對攔截器的應用提供了如下的驗證邏輯:

  • 標注到方法上(函數屬性的Get/Set方法):如果目標方法均不能被攔截,拋出異常;

  • 標注到屬性上:表示將攔截器應用到該屬性可以被攔截的Get/Set方法上。如果Get和Set方法均不能被攔截,拋出異常;

  • 標注到類型上:表示將攔截器應用到目標類型可以來攔截的方法(含屬性方法)上,如果類型的所有方法均不能被攔截,此時不會拋出異常。

public?class?Foo
{[FoobarInterceptor]public?void?M()?{?}
}public?class?Bar
{[FoobarInterceptor]public?object??P?{?get;?set;?}
}[FoobarInterceptor]
public?class?Baz
{public?void?M()?{?}
}

對于上面定義的三個類型,Foo的M方法和Bar的P屬性均是無法被攔截,Baz類型并沒有可以被攔截的方法。我們采用如下的程序測試上述的檢驗邏輯。

GetService<Foo>();
GetService<Bar>();
GetService<Baz>();static?void?GetService<T>()?where?T:class
{try{Console.WriteLine($"{typeof(T).Name}:");_?=?new?ServiceCollection().AddSingleton<T>().BuildInterceptableServiceProvider().GetRequiredService<T>();Console.WriteLine("OK");}catch?(Exception?ex){Console.WriteLine(ex.Message);}
}

程序運行后會在控制臺上輸出如下的結果,可以看出只有將攔截器應用到不合法的方法和屬性上才會拋出異常(源代碼)。

e8ee1da80c22f2c4e2c15e93cd835601.png

五、針對類型、屬性的標注

我們利用如下這個攔截器類型FoobarInterceptorAttribute 來演示將攔截器應用到類型和屬性上。該攔截器類型派生于InterceptorAttribute特性,并在執行的時候輸出當前的方法。

public?class?FoobarInterceptorAttribute?:?InterceptorAttribute
{public?ValueTask?InvokeAsync(InvocationContext?invocationContext){var?method?=?invocationContext.MethodInfo;Console.WriteLine($"{method.DeclaringType!.Name}.{method.Name}?is?intercepted.");return?invocationContext.ProceedAsync();}
}

我們將FoobarInterceptorAttribute 特性標注到Foo類型上,后者定義的M1方法和P1屬性是可以被攔截的,但是M2方法和P2屬性則不能。FoobarInterceptorAttribute 特性還被應用到Bar類型的P1屬性以及P2屬性的Set方法上。

[FoobarInterceptor]
public?class?Foo
{public?virtual?void?M1()?{?}public?void?M2()?{?}public?virtual?object??P1?{?get;?set;?}public?object??P2?{?get;???set;?}
}public?class?Bar
{[FoobarInterceptor]public?virtual?object??P1?{?get;?set;?}public?virtual?object??P2?{?get;?[FoobarInterceptor]?set;?}
}

我們利用如下的程序來檢驗針對Foo和Bar對象所有方法和屬性的調用,那么被攔截器攔截下來。

var?provider?=?new?ServiceCollection().AddSingleton<Foo>().AddSingleton<Bar>().BuildInterceptableServiceProvider();var?foo?=?provider.GetRequiredService<Foo>();
var?bar?=?provider.GetRequiredService<Bar>();foo.M1();
foo.M2();
foo.P1?=?null;
_?=?foo.P1;
foo.P2?=?null;
_?=?foo.P2;
Console.WriteLine();bar.P1?=?null;
_?=?bar.P1;
bar.P2?=?null;
_?=?bar.P2;

程序運行之后會在控制臺上輸出如下的結果(源代碼)。

cec6419766c2d675005b27318d2c8587.png

六、攔截的屏蔽

如果某個攔截器需要被應用大某個類型的絕大部分成員,我們可以選擇“排除法”:將攔截器應用到該類型上,將某些非目標成員屏蔽掉。還有一種情況下,如果我們確定某些類型或者方法不能被攔截(比如會在一個循環中頻繁調用),又擔心一些“模糊”的攔截器注冊方法將它們與某些攔截器錯誤地關聯在一起,此時我們可以選擇將其攔截功能顯式屏蔽掉。

針對攔截的屏蔽可以通過在類型、屬性、方法設置程序集上標注NonInterceptableAttribute特性。由于屏蔽功能具有最高優先級,一旦將此特性應用到某個類型上,該類型上的所有成員均不會被攔截。如果被標注到屬性上,其Get和Set方法也不會被攔截。具有如下定義的Foo和Bar類型的所有方法和屬性都不會被攔截(源代碼)。

[FoobarInterceptor]
public?class?Foo
{[NonInterceptable]public?virtual?void?M()?{?}[NonInterceptable]public?virtual?object??P1?{?get;?set;?}public?virtual?object??P2?{?[NonInterceptable]?get;?set;?}
}[NonInterceptable]
public?class?Bar
{[FoobarInterceptor]public?virtual?void?M()?{?}[FoobarInterceptor]public?virtual?object??P?{?get;?set;?}
}

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

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

相關文章

在慘遭勒索病毒攻擊之后,微軟呼吁重新制定“數字日內瓦公約”

基于美國安全局泄露文檔開發的病毒程序成為上周的主要新聞&#xff0c;該病毒導致全世界大量的Windows電腦癱瘓。WannaCry勒索病毒在150個國家有20萬個受害者&#xff0c;包括英國的醫院、西班牙的基礎設施部門和俄羅斯的內政部。Renault在受到攻擊之后關閉了幾家在法國境內的工…

【代碼審計】PHP代碼審計---基礎記錄

PHP偽協議 PHP偽協議事實上是其支持的協議與封裝協議&#xff0c;支持的種類有以下12種。 * file:// — 訪問本地文件系統 * http:// — 訪問 HTTP(s) 網址 * ftp:// — 訪問 FTP(s) URLs * php:// — 訪問各個輸入/輸出流&#xff08;I/O streams&#xff09; * zlib:// — 壓…

全新升級的AOP框架Dora.Interception[4]: 基于表達式的攔截器注冊

基于特性標注的攔截器注冊方式僅限于將攔截器應用到自己定義的類型上&#xff0c;對于第三方提供的類型就無能為力了。對于Dora.Interception來說&#xff0c;攔截器注冊本質上建立攔截器與一個或者多個目標方法之間的映射&#xff0c;所以最笨的方式就是利用反射的方式得到表示…

mysql8.0.12插件_MySQL8.0.12 安裝及配置

MySQL8.0.12 安裝及配置發布時間&#xff1a;2018-08-07 10:39,瀏覽次數&#xff1a;274, 標簽&#xff1a;MySQL一.安裝1.從網上下載MySQL8.0.12版本&#xff0c;下載地址&#xff1a;https://dev.mysql.com/downloads/mysql/2. 下載完成后解壓我解壓的路徑是&#xff1a;D:\J…

python模塊之hashlib

hashlib模塊實現了多種安全哈希和信息摘要算法的通用接口&#xff0c;包括FIPS中定義的SHA1, SHA224, SHA256, SHA384, SHA512以及RFC 1321中定義的MD5 注意點&#xff1a;1. adler32及crc32哈希由zlib模塊提供2. 某些算法已知存在哈希碰撞弱點 哈希算法 每個hash算法都有一個同…

記一次阿里電面經歷

昨天下午&#xff08;3/19&#xff09;三點多鐘&#xff0c;接到了一個杭州的電話&#xff0c;是阿里的。問我是否方便聊聊。我說我在上課&#xff0c;四點下課。然后他就四點多鐘的時候又打了一次過來。項目經歷上來就問我有無大型項目的經歷。不好意思&#xff0c;我說無。。…

C語言程序設計第三次作業

&#xff08;一&#xff09;改錯題 計算f(x)的值&#xff1a;輸入實數x&#xff0c;計算并輸出下列分段函數f(x)的值&#xff0c;輸出時保留1位小數。 輸入輸出樣例1&#xff1a;   Enterr x: 10.0   f(10.0) 0.1 輸入輸出樣例2&#xff1a;   Enter x: 234   f(234.0…

mysql數據庫項目化教程鄭小蓉_MySQL數據庫項目化教程(高等職業教育“十三五”規劃教材(軟件技術專業))...

《MySQL數據庫項目化教程/高等職業教育十三五規劃教材(軟件技術專業)》是一本介紹MySQL數據庫基礎知識的入門教材&#xff0c;采用項目驅動方式循序漸進地介紹MySQL各個模塊的知識。主要內容包括&#xff1a;Windows下MySQL的安裝&#xff0c;MySQL服務的啟動與停止&#xff0c…

WPF-09 ManualResetEventSlim信號量

業務場景如下&#xff1a;WPF應用程序后臺有個定時任務在接收PLC硬件數據(該線程接收完數據之后, 會重新啟動一個新線程繼續接收.....)&#xff0c;當應用程序關閉時, 我們得確保接收PLC硬件數據的線程完成之后,再關閉應用程序&#xff0c;否則會造成數據丟失。上面的業務場景是…

【bzoj3033】太鼓達人 DFS歐拉圖

題目描述 給出一個整數K&#xff0c;求一個最大的M&#xff0c;使得存在一個每個位置都是0或1的圈&#xff0c;圈上所有連續K位構成的二進制數兩兩不同。輸出最大的M以及這種情況下字典序最小的方案。 輸入 一個整數K。 輸出 一個整數M和一個二進制串&#xff0c;由一個空格分隔…

Redis 集合處理

學習了列表之后&#xff0c;發現了Redis處理字符串的功能強大。 為了適應不同場景的需求&#xff0c;還有一個用的很多的就是集合。 Redis提供的集合支持的類型是字符串。并且集合中的元素值是唯一的&#xff0c;也就是說不能出現重復數據。 而且&#xff0c;集合的實現是通過哈…

fpga mysql_FPGA的一些瑣碎知識整理

1.生產FPGA的廠家有&#xff1a;ALTERAXILINXATCELLatticeps:Altera和Xilinx主要生產一般用途FPGA&#xff0c;其主要產品采用SRAM工藝Actel主要提供非易失性FPGA&#xff0c;產品主要基于反熔絲工藝和FLASH工藝ps: 熔絲&#xff0c;顧名思義&#xff1a;把絲熔掉&#xff0c;反…

使用增量備份修復DG中的GAP

問題描述 oracle中DG出現主備不同步現象&#xff0c;alert日志報警有gap信息&#xff0c;但是v$archive_gap視圖查不到任何信息。同時主庫上的對應歸檔已經刪除且沒有備份 解決方案 1.查詢備庫的scn SQL> select current_scn from v$database; 這時有可能出來的scn是以科學計…

C# 反射類Assembly用法舉例

概述程序運行時&#xff0c;通過反射可以得到其它程序集或者自己程序集代碼的各種信息&#xff0c;包括類、函數、變量等來實例化它們&#xff0c;執行它們&#xff0c;操作它們&#xff0c;實際上就是獲取程序在內存中的映像&#xff0c;然后基于這個映像進行各種操作。Assemb…

團隊作業

團隊&組員&#xff1a; 沒有組名&#xff0c;大概是因為我們組雖然有10個人&#xff0c;但是好像只起到人多的地方就容易開車搞笑&#xff0c;沒有內涵&#xff0c;取出來的都是秋名山吳彥組這樣的開車組名&#xff0c;在大家的的強烈建議和玩笑中&#xff0c;決定了沒有組…

算法系列【希爾排序】篇

常見的內部排序算法有&#xff1a;插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序、基數排序等。用一張圖概括&#xff1a;關于時間復雜度&#xff1a;1. 平方階 (O(n2)) 排序各類簡單排序&#xff1a;直接插入、直接選擇和冒泡排序。2. 線性對數…

sql查詢索引語句_sql優化總結--基于sql語句優化和索引優化

概述最近做查詢&#xff0c;統計和匯總。由于數據量比較龐大&#xff0c;大部分表數據上百萬&#xff0c;甚至有的表數據上千萬。所以在系統中做sql優化比較多&#xff0c;特此寫一篇文章總結一下關于sql優化方面的經驗。導致查詢緩慢的原因1、數據量過大2、表設計不合理3、sql…

電商行業運維實踐

電商行業運維實踐&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;…

數據結構小總結(成都磨子橋技工學校數據結構前12題)

[pixiv] https://www.pixiv.net/member_illust.php?modemedium&illust_id34352147 暑假的作業&#xff0c;頹頹的我總算是寫完了 線段樹 線段樹是一個高級玩意&#xff0c;不僅可以求區間和&#xff0c;區間最大等等的簡單問題&#xff0c;靈活運用還有好多變種。自從學…

【九章算法免費講座第一期】轉專業找CS工作的“打狗棒法”

講座時間&#xff1a; 美西時間6月5日18&#xff1a;30-20&#xff1a;00&#xff08;周五&#xff09; 北京時間6月6日09&#xff1a;30-11&#xff1a;00&#xff08;周六a.m&#xff09; 講座安排&#xff1a; 免費在線直播講座 報名網址&#xff1a; http://t.cn/R2XgMSH&a…