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