技术开发 频道

.NET中通过代理实现面向方面编程

  【IT168技术】AOP是OOP的延续,Aspect Oriented Programming的缩写,即面向方面编程。AOP是GoF设计模式的延续,设计模式追求的是调用者和被调用者之间的解耦,AOP也是这种目标的一种实现。

  我说到了在代码中可以利用泛型委托来封装异常处理,这样可以让程序看起来更加清晰,要想完成功能需要调用者调用指定的工厂方法才行,但要想改变某些程序员的编码习惯我想是一件比较困难的事情。有朋友说利用委托来实现异常处理并不算是真正意义上的AOP,因为传统的AOP并不需要客户端做代码结构的变更,最多也就是配置上的问题。但在.net中要想实现AOP,我想最方便的实现机制要属代理机制了,但只要利用代理,在性能上就会造成一定的影响。

  如果开发过分布式服务,像remotion,wcf等,消息都是它们通信的重要手段。客户端通过方法调用形式体现的服务访问需要转换成具体的消息,然后经过编码才能利用传输通道发送给服务端,服务执行的结果也只能以消息的形式返回给调用方。

  这些分布式服务有一共同特点:都通过代理方法间接的调用服务。服务代理,它自身并不提供服务的实现,只是起到一个中介作用,客户端把服务请求发送给服务代理,服务代理再去调真正的服务,同样服务返回时,也是返回给服务代理,再由服务代理返回给客户端。看到这,我想对于实现AOP的拦截就有点眉目了。在.net中,我们可以写自定义的RealProxy来实现AOP的方法拦截功能。

  服务代理通常又分为以下两种:

  1:透明代理。客户端在跨任何类型的远程处理边界使用对象时,对对象使用的实际上是透明代理。透明代理使人以为实际对象驻留在客户端空间中。它实现这一点的方法是:使用远程处理基础结构将对其进行的调用转发给真实对象。透明代理本身由 RealProxy 类型的托管运行时类的实例收容。RealProxy 实现从透明代理转发操作所需的部分功能。代理对象继承托管对象(例如垃圾回收、对成员和方法的支持)的关联语义,可以将其进行扩展以形成新类。这样,该代理具有双重性质,一方面,它需要充当与远程对象(透明代理)相同的类的对象;另一方面,它本身是托管对象。

  2:真实代理。RealProxy来实现与远程服务进行通信,所以这里就是我们实现AOP的地方。

  下图是透明代理与真实代理以及远程对象的调用关系图:

  下图是利用自定义的RealProxy实现AOP方法拦截的原理图:

  自定义异常代理类:

  说明:1>自定义的代理类需要继承RealProxy。

  2>从 RealProxy 继承时,必须重写 Invoke方法。

  3>下面代码中的LogManage是一个log4net接口,我们可以把异常统一记录到日志中,供日后分析。

/// /// Aspect代理,在这个类里面,实现对方法的拦截 /// public class AspectProxyErrorLog : RealProxy { AspectManagedAttribute attr; /// /// 默认构造函数 /// public AspectProxyErrorLog() : base() { } /// /// 构造函数 /// /// 被代理的类的类型 public AspectProxyErrorLog(Type myType) : base(myType) { } /// /// 构造函数 /// /// 被代理的类的类型 /// 被代理的对象 public AspectProxyErrorLog(Type myType,MarshalByRefObject obj) : base(myType) { target=obj; } MarshalByRefObject target; ILog LogManage; /// /// 当在派生类中重写时,在当前实例所表示的远程对象上调用在所提供的 IMessage 中指定的方法。
/// WebsharpAspect在这里执行对方法执行的拦截处理 /// /// IMessage,包含有关方法调用的信息。 /// 调用的方法所返回的消息,包含返回值和所有 out 或 ref 参数。 public override IMessage Invoke(IMessage msg) { IMessage retMsg=null ; IMethodCallMessage methodCall = (IMethodCallMessage)msg; IMethodReturnMessage methodReturn = null; object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[]; methodCall.Args.CopyTo(copiedArgs, 0); object[] attrs = null; CoustomerErrorHandleAttribute ceha = null; if (msg is IConstructionCallMessage) { IConstructionCallMessage ccm = (IConstructionCallMessage)msg; RemotingServices.GetRealProxy(target).InitializeServerObject(ccm); ObjRef oRef = RemotingServices.Marshal(target); RemotingServices.Unmarshal(oRef); retMsg = EnterpriseServicesHelper.CreateConstructionReturnMessage(ccm, (MarshalByRefObject)this.GetTransparentProxy()); } else { IMethodCallMessage mcm = (IMethodCallMessage)msg; attrs = methodCall.MethodBase.GetCustomAttributes(typeof(CoustomerErrorHandleAttribute), false); ceha = LogManagerFactory.GetCoustomerErrorHandleAttribute(attrs, methodCall.MethodBase.Name ); if (null != ceha) { LogManage = ceha.ILogName; } try { object returnValue = methodCall.MethodBase.Invoke(this.target, copiedArgs); methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall); } catch (Exception ex) { if (null != ex.InnerException) { methodReturn = new ReturnMessage(ex.InnerException, methodCall); } else { methodReturn = new ReturnMessage(ex, methodCall); } } retMsg = methodReturn; } if (null != methodReturn) { if (null != methodReturn.Exception ) { if (null != this.LogManage ) { this.LogManage.Error(ceha .MethodErrorText + methodReturn.Exception.ToString()); } } } return retMsg; } }

  

0
相关文章