Autofac的切面编程实现
面向切面編程:Autofac.Annotation擴展組件是我開源的一款利用打標簽完成autofac容器的注入組件。
https://github.com/yuzd/Autofac.Annotation
我們之前介紹了利用Aspect標簽來完成攔截器功能
Aspect是一對一的方式,我想要某個class開啟攔截器功能我需要針對每個class去配置。?詳情請點擊
比如說 我有2個 controller 每個controller都有2個action方法,
[Component]public class ProductController{public virtual string GetProduct(string productId){return "GetProduct:" + productId;}public virtual string UpdateProduct(string productId){return "UpdateProduct:" + productId;}}[Component]public class UserController{public virtual string GetUser(string userId){return "GetUser:" + userId;}public virtual string DeleteUser(string userId){return "DeleteUser:" + userId;}}如果我需要這2個controller的action方法都在執行方法前打log 在方法執行后打log 按照上一節Aspect的話 我需要每個controller都要配置。如果我有100個controller的畫我就需要配置100次,這樣我覺得太麻煩了。所以我參考了Spring的Pointcut切面編程的方式實現了一套類似的,下面看如何用Pointcut的方式方便的配置一種切面去適用于N個對象。
定義一個切面:創建一個class 上面打上Pointcut的標簽 如下:
Pointcut標簽類有如下屬性:
| Name | 名稱Pointcut切面的名稱(默認為空,和攔截方法進行匹配,參考下面說明) |
| RetType | 匹配目標類的方法的返回類型(默認是%) |
| NameSpace | 匹配目標類的namespace(默認是%) |
| ClassName | 匹配目標類的類名稱(必填) |
| MethodName | 匹配目標類的方法名稱(默認是%) |
匹配算法
?舉例:
| 匹配結果:true | "%" | "" |
| 匹配結果:true | "%" | " " |
| 匹配結果:true | "%" | "asdfa asdf asdf" |
| 匹配結果:true | "%" | "%" |
| 匹配結果:false | "_" | "" |
| 匹配結果:true | "_" | " " |
| 匹配結果:true | "_" | "4" |
| 匹配結果:true | "_" | "C" |
| 匹配結果:false | "_" | "CX" |
| 匹配結果:false | "[ABCD]" | "" |
| 匹配結果:true | "[ABCD]" | "A" |
| 匹配結果:true | "[ABCD]" | "b" |
| 匹配結果:false | "[ABCD]" | "X" |
| 匹配結果:false | "[ABCD]" | "AB" |
| 匹配結果:true | "[B-D]" | "C" |
| 匹配結果:true | "[B-D]" | "D" |
| 匹配結果:false | "[B-D]" | "A" |
| 匹配結果:false | "[^B-D]" | "C" |
| 匹配結果:false | "[^B-D]" | "D" |
| 匹配結果:true | "[^B-D]" | "A" |
| 匹配結果:true | "%TEST[ABCD]XXX" | "lolTESTBXXX" |
| 匹配結果:false | "%TEST[ABCD]XXX" | "lolTESTZXXX" |
| 匹配結果:false | "%TEST[^ABCD]XXX" | "lolTESTBXXX" |
| 匹配結果:true | "%TEST[^ABCD]XXX" | "lolTESTZXXX" |
| 匹配結果:true | "%TEST[B-D]XXX" | "lolTESTBXXX" |
| 匹配結果:true | "%TEST[^B-D]XXX" | "lolTESTZXXX" |
| 匹配結果:true | "%Stuff.txt" | "Stuff.txt" |
| 匹配結果:true | "%Stuff.txt" | "MagicStuff.txt" |
| 匹配結果:false | "%Stuff.txt" | "MagicStuff.txt.img" |
| 匹配結果:false | "%Stuff.txt" | "Stuff.txt.img" |
| 匹配結果:false | "%Stuff.txt" | "MagicStuff001.txt.img" |
| 匹配結果:true | "Stuff.txt%" | "Stuff.txt" |
| 匹配結果:false | "Stuff.txt%" | "MagicStuff.txt" |
| 匹配結果:false | "Stuff.txt%" | "MagicStuff.txt.img" |
| 匹配結果:true | "Stuff.txt%" | "Stuff.txt.img" |
| 匹配結果:false | "Stuff.txt%" | "MagicStuff001.txt.img" |
| 匹配結果:true | "%Stuff.txt%" | "Stuff.txt" |
| 匹配結果:true | "%Stuff.txt%" | "MagicStuff.txt" |
| 匹配結果:true | "%Stuff.txt%" | "MagicStuff.txt.img" |
| 匹配結果:true | "%Stuff.txt%" | "Stuff.txt.img" |
| 匹配結果:false | "%Stuff.txt%" | "MagicStuff001.txt.img" |
| 匹配結果:true | "%Stuff%.txt" | "Stuff.txt" |
| 匹配結果:true | "%Stuff%.txt" | "MagicStuff.txt" |
| 匹配結果:false | "%Stuff%.txt" | "MagicStuff.txt.img" |
| 匹配結果:false | "%Stuff%.txt" | "Stuff.txt.img" |
| 匹配結果:false | "%Stuff%.txt" | "MagicStuff001.txt.img" |
| 匹配結果:true | "%Stuff%.txt" | "MagicStuff001.txt" |
| 匹配結果:true | "Stuff%.txt%" | "Stuff.txt" |
| 匹配結果:false | "Stuff%.txt%" | "MagicStuff.txt" |
| 匹配結果:false | "Stuff%.txt%" | "MagicStuff.txt.img" |
| 匹配結果:true | "Stuff%.txt%" | "Stuff.txt.img" |
| 匹配結果:false | "Stuff%.txt%" | "MagicStuff001.txt.img" |
| 匹配結果:false | "Stuff%.txt%" | "MagicStuff001.txt" |
| 匹配結果:true | "%Stuff%.txt%" | "Stuff.txt" |
| 匹配結果:true | "%Stuff%.txt%" | "MagicStuff.txt" |
| 匹配結果:true | "%Stuff%.txt%" | "MagicStuff.txt.img" |
| 匹配結果:true | "%Stuff%.txt%" | "Stuff.txt.img" |
| 匹配結果:true | "%Stuff%.txt%" | "MagicStuff001.txt.img" |
| 匹配結果:true | "%Stuff%.txt%" | "MagicStuff001.txt" |
| 匹配結果:true | "?Stuff?.txt?" | "1Stuff3.txt4" |
| 匹配結果:false | "?Stuff?.txt?" | "1Stuff.txt4" |
| 匹配結果:false | "?Stuff?.txt?" | "1Stuff3.txt" |
| 匹配結果:false | "?Stuff?.txt?" | "Stuff3.txt4" |
定義好了一個Pointcut切面后 需要定義這個切面的攔截方法
配合Pointcut切面標簽,可以在打了這個標簽的class下定義攔截方法, 在方法上得打上特定的標簽,有如下幾種:
| Before標簽 | 在匹配成功的類的方法執行前執行 |
| After標簽 | 在匹配成功的類的方法執行后執行 |
| Around標簽 | 承接了 匹配成功的類的方法的執行權(如果一個切面配置了Around又配置了Before或者After,那么會只執行Around) |
以上3種標簽有一個可選的參數:Name (默認為空,可以和Pointcut的Name進行mapping)
因為一個class上可以打多個Pointcut切面,一個Pointcut切面可以根據name去匹配對應攔截方法
如果是用Around環繞的話
// *Controller 代表匹配 只要是Controller結尾的類都能匹配// Get* 代表上面匹配成功的類下 所以是Get打頭的方法都能匹配[Pointcut(ClassName = "*Controller",MethodName = "Get*")]public class LoggerPointCut{/// <summary>/// 打上Around標簽 承接了 匹配成功的類的方法的執行權/// </summary>/// <param name="context"></param>[Around]public void Around(AspectContext context){//執行原目標方法前Console.WriteLine(context.InvocationContext.MethodInvocationTarget.Name + "-->Start");//執行原目標方法context.InvocationProceedInfo.Invoke();//執行原目標方法后Console.WriteLine(context.InvocationContext.MethodInvocationTarget.Name + "-->End");}}執行方法的參數說明:
執行方法的參數可以是DI容器的類型,會在執行時自動注入進來,可以使用Autowired,Value等標簽來修飾參數。
還有一個特殊的執行參數可以注入,那就是AspectContext,這個類型里面你可以獲取到被攔截的方法的信息,以及執行原方法的委托。
注意:這個執行后 有2種
正常執行成功
有異常,若方法參數注入了AspectContext 那么可以通過Exception屬性值獲得異常內容
按照上面的配置
ProductController.GetProduct 會被匹配
UserController.GetUser 會被匹配
在執行上面這2個方法的時候會
先執行 LoggerPointCut.Before方法
再執行 LoggerPointCut.After方法
利用Autofac的這個開源擴展組件很方便的實現切面編程,總結切面編程三步驟
1.定義一個切面,編寫要匹配的目標類的方法(采用sql的like方式匹配),所以一個切面可以攔截n個目標
2.定義對應的攔截方法
3.執行被匹配的方法時會執行對應的攔截方法
總結
以上是生活随笔為你收集整理的Autofac的切面编程实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mobius 一个运行在 .NET Co
- 下一篇: .net core 基于Dapper 的