目 录
最近需要有一个完全自主的基于C#语言的Aop框架,查了一下资料实现方式主要分为:静态织入和动态代理,静态织入以Postshop为代表,而动态代理又分为:
1、普通反射
2、Emit反射
3、微软提供的.Net Remoting和RealProxy
(微软官方例子)
总体来说静态织入速度最快,普通反射最慢,而.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("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_NameLog OnEntry:set_Age(10)Log OnExit: set_AgeLog OnEntry:NYearLater(10)Log OnEntry:get_Age()Log OnExit: get_Age Result: 10Log OnExit: NYearLater Result: 20done...
通过结果可以看到 属性Name、Age的Set方法,NYearLater方法,以及Age属性的Get方法都实现了日志记录。下边将分几篇来详细介绍DynamicProxy类的实现。欢迎大家多多指正、交流。