前几天开发项目中需要用到AOP,于是翻看了一些开源的AOP框架资料,这些框架功能都很强大,不过对于我来说这些强大的功能确显得有些繁琐,于是就想自己动手开发一个简单实用AOP框架。说干就干,查了一些资料决定采用Emit注入生成代理类的方式实现。
思路:分为两种情况,第一种是原始类从接口或抽象类继承而来,第二种就是没有继承接口或者抽象类。对以第一种情况我们生成的代理类只要同样继承接口或者抽象类然后引用原始类实例就可以,在方法中直接调用原始类中相应的方法,第二种情况继承原始类然后重写要注入的方法,这就要求原始类要实现切面的方法必须是虚方法。
假设我们有一个类Info.cs这个类继承自IInfo.cs接口,我们的目的是为Info实现一个代理类在这个代理类中能过后做两件事:1.调用切面方法 2.调用原始类中的方法。下面两个图说明实现代理类的两种情况:
图1
图2
当然我们不可能手动的去写一个这样的代理类,我们应该动态产生一个代理类,这让我们想到了Emit,使用过Emit的人都知道它功能非常强大,有人说他是MS提供的万能中间语言介入机制。OK 我们现在要做的就是通过Emit发射中间语言动态生成一个代理类。
思路清晰了,就让我们开始具体行动吧。创建一个项目SimpleAOP,如下图:
图3
图4
BaseAttribute:在AOP方法上标注属性的基类,只有一个属性CallHandlerType,它记录表示了该属性的方法使用哪个Handler来拦截方法。
ICallHandler:向拦截方法中注入代码类的接口
Wraper:包装类,该类对原始类进行包装产生代理类。
MethodContext:被拦截方法的上下文,包括Executor:原始类的实力,MethodInfo:被拦截方法信息,ParametersValue:参数信息
代码如下:
}
}
}
}
}
}
}
}
}
}
}
Wraper中使用Emit首先在代理中生成一个T类型的公有字段用来存放原始对象,遍历T类型中的所有虚方法(接口方法都是虚方法),对标有BaseAttribute类型属性的方法进行实现或者重写,在实现或重写中首先创建MethodContext,然后获取CallHandlerType并创建CallHandler对象,最后调用CallHandler对象的Invoke方法,CallHandler对象中调用MethodContext对象中的Invoke方法调用原方法, 至此我成功拦截执行方法。
使用:
我们用Cahce进行举例说明,首先创建一个类CacheAttribute继承BaseAttribute,代码如下:
}
}
}
}
新建一个类CacheCallHandler继承实现ICallHandler 代码如下:
}
}