最近需要有一個完全自主的基於C#語言的Aop框架,查了一下資料實現方式主要分為:靜態織入和動態代理,靜態織入以Postshop為代表,而動態代理又分為: 1、普通反射 2、Emit反射 3、微軟提供的.Net Remoting和RealProxy (微軟官方例子https://msdn.micros ...
最近需要有一個完全自主的基於C#語言的Aop框架,查了一下資料實現方式主要分為:靜態織入和動態代理,靜態織入以Postshop為代表,而動態代理又分為:
1、普通反射
2、Emit反射
3、微軟提供的.Net Remoting和RealProxy
(微軟官方例子https://msdn.microsoft.com/zh-cn/library/dn574804.aspx)
總體來說靜態織入速度最快,普通反射最慢,而.Net Remoting和RealProx實現起來又相對較複雜。而Emit速度居中,同時其一次生成後,將結果序列化,速度也並不慢,同時和原有類並沒有緊密耦合,通過外部配置文件可以方便的控制要進行代理的類型、方法和屬性,其缺點是被代理的方法、屬性必須為virtual類型。
一、被代理類和代理類
被代理類,是我們正常使用的類,裡邊是原有的業務邏輯,只要在被代理方法上申明上相應的切麵特性就行了,使用起來比較簡單;如下
1 public class AopTest 2 { 3 4 public AopTest() 5 { 6 Name = "小明"; Age = 10; 7 } 8 9 public AopTest(string name, int age) 10 { 11 Name = name; Age = age; 12 } 13 14 [Log] 15 public virtual string Name { get; set; } 16 17 [Log] 18 public virtual int Age { get; set; } 19 20 [Log] 21 public virtual int NYearLater(int a) 22 { 23 int larter = Age + a; 24 25 return larter; 26 } 27 }
代理類是Aop框架自動生成的類,使用反編譯工具我們可以看到,它比被代理類多了切麵上下文聲明(AspectContent)和相應的切麵特性對象聲明,在被代理類的方法執行前後,相應切麵特性調用OnEntry、OnExit執行相關操作,如日誌、參數驗證、許可權驗證等等Aop功能,其中AspectContext是OnEntry、OnExit調用參數,如下:
public class AopTest_Proxy : AopTest { public override string Name { get { object[] args = new object[0]; AspectContext aspectContext = new AspectContext(this, "get_Name", args); LogAttribute logAttribute = new LogAttribute(); logAttribute.OnEntry(aspectContext); string name = base.Name; aspectContext.Result = name; logAttribute.OnExit(aspectContext); return name; } set { AspectContext context = new AspectContext(this, "set_Name", new object[] { value }); LogAttribute logAttribute = new LogAttribute(); logAttribute.OnEntry(context); base.Name = value; logAttribute.OnExit(context); } } public override int Age { get { object[] args = new object[0]; AspectContext aspectContext = new AspectContext(this, "get_Age", args); LogAttribute logAttribute = new LogAttribute(); logAttribute.OnEntry(aspectContext); int age = base.Age; aspectContext.Result = age; logAttribute.OnExit(aspectContext); return age; } set { AspectContext context = new AspectContext(this, "set_Age", new object[] { value }); LogAttribute logAttribute = new LogAttribute(); logAttribute.OnEntry(context); base.Age = value; logAttribute.OnExit(context); } } public AopTest_Proxy(string name, int age) : base(name, age) { } public override int NYearLater(int num) { AspectContext aspectContext = new AspectContext(this, "NYearLater", new object[] { num }); LogAttribute logAttribute = new LogAttribute(); logAttribute.OnEntry(aspectContext); int num2 = base.NYearLater(num); aspectContext.Result = num2; logAttribute.OnExit(aspectContext); return num2; } }
二、測試方法
public static void Test() { try { AopTest WithPara = DynamicProxy.Create<AopTest>("lxl", 10); ; WithPara.NYearLater(10); Console.WriteLine("done..."); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
測試方法中:AopTest WithPara = DynamicProxy.Create<AopTest>("lxl", 10); ,生成一個代理對象,其他就正常使用就可以了。
調用測試方法執行結果如下:
Log OnEntry:set_Name(lxl) Log OnExit: set_Name Log OnEntry:set_Age(10) Log OnExit: set_Age Log OnEntry:NYearLater(10) Log OnEntry:get_Age() Log OnExit: get_Age Result: 10 Log OnExit: NYearLater Result: 20 done...
通過結果可以看到 屬性Name、Age的Set方法,NYearLater方法,以及Age屬性的Get方法都實現了日誌記錄。下邊將分幾篇來詳細介紹DynamicProxy類的實現。歡迎大家多多指正、交流。