最近翻手头的dll文件时无意中发现了一个Interception实现,这个框架比起目前流行的AOP框架显的比较简漏,但却很好的体现出了.net下AOP是怎么实现的,于是就整理出来。
在.Net Unity2.0中的Interception,按三种方式实现:
1.TransparentProxy/RealProxy Interceptor 即Remoting代理机制。
2.Interface Interceptor 即动态代码 (Emit编程)实现
3.Virtual Method Interceptor 也是动态代码实现,Emit编程基本类似于IL编程了。
实例拦截与类型拦截
1.实例拦截
TransparentProxy 与 Interface Interceptor 属于实例拦截,所谓实例拦截就是被拦截对象完整而独立的在内参中存在。Client端通过代理类与被拦截对象发生通信(方法调用)。
2.类型拦截
Virtual Method 方式属于类型拦截,内参中不存在被拦截类型的实例,拦截框架通过动态代码生成被拦截类型的子类型程序集,该程序集被加载后对应的子类型被实例化于内存中与Client发生通信
下面针对TransparentProxy/RealProxy 与 Interface Interceptor帖出手头上dll实现的代码
1.TransparentProxy/RealProxy实现
using System.Runtime.Remoting.Proxies; |
using System.Runtime.Remoting.Messaging; |
using System.Runtime.Remoting; |
internal class TransparentProxy : RealProxy |
private readonly MarshalByRefObject m_Target; |
public TransparentProxy(MarshalByRefObject target) |
public static object GetProxy(MarshalByRefObject target) |
TransparentProxy proxy = new TransparentProxy(target); |
return proxy.GetTransparentProxy(); |
public override IMessage Invoke(IMessage msg) |
IMethodCallMessage callMsg = msg as IMethodCallMessage; |
object [] customAttributes = callMsg.MethodBase.GetCustomAttributes( true ); |
this .InvokeBeforeAttribute(customAttributes, callMsg); |
message = RemotingServices.ExecuteMessage( this .m_Target, callMsg); |
catch (Exception exception) |
this .InvokeExceptionAttribute(customAttributes, callMsg, exception); |
this .InvokeAfterAttribute(customAttributes, callMsg, ((ReturnMessage)message).ReturnValue); |
类TransproxyProxy中维护着一个到target类实例的引用(必须是MarshalByRefObject类型的子类),最终的方法调用会通过消息机制到达target实例--语句RemotingServices.ExecuteMessage(this.m_Target, callMsg);,在调用目标对象的目标方法之前会调用InvokeBeforeAttribute,错误时会调用InvokeExceptionAttribute,而完成后调用InvokeAfterAttribute.这里需要注意的是Unity2.0 Interception 中将要调用的InterceptionBehavior构建成管道模型,编程时会有Scop样的开闭结构,而这里的实现只是顺序的调用,这点需要加以区分。InvokeBeforeAttribute等方法实现如下
private void InvokeAfterAttribute( object [] attributes, IMethodCallMessage callMsg, object result) |
foreach ( object obj2 in attributes) |
AfterAttribute attribute = obj2 as AfterAttribute; |
attribute.Invoke( this .m_Target, callMsg.MethodBase, callMsg.InArgs, result); |
List<IInterception> interceptionList = ProxyBuilder.GetInterceptionList( this .m_Target.GetType().FullName + "." + callMsg.MethodName, InterceptionType.After); |
if (interceptionList != null ) |
foreach (IInterception interception in interceptionList) |
interception.Invoke( this .m_Target, callMsg.MethodBase, callMsg.InArgs, result); |
2.Interface Interceptor 代码
public static object GetProxyInstance( object target, Type interfaceType) |
return Activator.CreateInstance(GetProxyType(target.GetType(), interfaceType), new object [] { target, interfaceType }); |
private static Type GetProxyType(Type targetType, Type interfaceType) |
AppDomain domain = Thread.GetDomain(); |
AssemblyName name = new AssemblyName(); |
name.Name = "TempAssemblyInjection" ; |
AssemblyName name2 = name; |
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(name2, AssemblyBuilderAccess.Run); |
ModuleBuilder builder = assemblyBuilder.DefineDynamicModule( "TempClassInjection" ); |
Type type = builder.GetType( "TempAssemblyInjection__Proxy" + interfaceType.Name + targetType.Name); |
m_TypeBuilder = builder.DefineType( "TempAssemblyInjection__Proxy" + interfaceType.Name + targetType.Name, TypeAttributes.Public, targetType.BaseType, new Type[] { interfaceType }); |
m_Target = m_TypeBuilder.DefineField( "target" , interfaceType, FieldAttributes.Private); |
m_Interface = m_TypeBuilder.DefineField( "iface" , typeof (Type), FieldAttributes.Private); |
CreateConstructor(m_TypeBuilder, m_Target, m_Interface); |
foreach (MethodInfo info in interfaceType.GetMethods()) |
CreateProxyMethod(info, m_TypeBuilder); |
return m_TypeBuilder.CreateType(); |
上面代码通过Emit编程动态构建程序集,程序集中包括一个到目标类的代理类,针对给定接口中的方法签名逐个创建代理方法--语句CreateProxyMethod(info, m_TypeBuilder);
另外可以看到代理类型的程序集只在第一次访问时被创建
--语句
Type type = builder.GetType("TempAssemblyInjection__Proxy" + interfaceType.Name + targetType.Name);
if (type != null)
{
return type;
}
建立的代理类定义类似如下代码:
public class TempAssemblyInjection__ProxyIAnimalDog : IAnimal |
public TempAssemblyInjection__ProxyIAnimalDog( object obj1, Type type1) |
this .target = (IAnimal) obj1; |
public override int Run( int num1, int num2) |
object [] parameters = new object [] { num1, num2 }; |
return ( int ) DynamicProxy.InterceptHandler( this .target, <BR> Helper.GetMethodFromType( this .target.GetType(), MethodBase.GetCurrentMethod()),<BR> parameters, <BR> Helper.AspectUnion(Helper.GetMethodFromType( this .iface, MethodBase.GetCurrentMethod()).GetCustomAttributes( typeof (AspectAttribute), true ))<BR> ); |
DynamicProxy.InterceptHandler的代码
public static object InterceptHandlerMethod( object target, MethodBase method, object [] parameters, AspectAttribute[] attributes) |
foreach (AspectAttribute attribute in attributes) |
if (attribute is BeforeAttribute) |
attribute.Invoke(target, method, parameters, null ); |
foreach (IInterception interception in ProxyBuilder.GetInterceptionList(target.GetType().FullName + "." + method.Name, InterceptionType.Before)) |
interception.Invoke(target, method, parameters, null ); |
obj2 = target.GetType().GetMethod(method.Name).Invoke(target, parameters); |
catch (Exception exception) |
foreach (AspectAttribute attribute2 in attributes) |
if (attribute2 is ExceptionAttribute) |
attribute2.Invoke(target, method, parameters, exception); |
foreach (IInterception interception2 in ProxyBuilder.GetInterceptionList(target.GetType().FullName + "." + method.Name, InterceptionType.Exception)) |
interception2.Invoke(target, method, parameters, exception); |
foreach (AspectAttribute attribute3 in attributes) |
if (attribute3 is AfterAttribute) |
attribute3.Invoke(target, method, parameters, obj2); |
foreach (IInterception interception3 in ProxyBuilder.GetInterceptionList(target.GetType().FullName + "." + method.Name, InterceptionType.After)) |
interception3.Invoke(target, method, parameters, obj2); |
public static Callback InterceptHandler |
return new Callback(DynamicProxy.InterceptHandlerMethod); |
原文链接:http://www.cnblogs.com/wdfrog/archive/2011/03/18/1988091.html