上一节实现了动态代理,接下来 有时候,我不需要在每一个方法都要记录日志,做权限验证 等等。 所有就有了这样的需求。AOP实现特定方法过滤,有选择性的来对方法实现AOP 拦截。就是本节标题所示。

举个例子,对于查询的方法我不需要记录日志,所以,我就找到如果以“Get”开头的方法,就不记录日志,否则就记录日志;所以基于这样一个需求,代码如下:

public override IMessage Invoke(IMessage msg)
{
  var methodCall = msg as IMethodCallMessage;
  var methodInfo = methodCall.MethodBase as MethodInfo;
  if (!methodInfo.Name.StartsWith("Get"))
    Log("In Dynamic Proxy - Before executing '{0}'",
      methodCall.MethodName);
  try
  {
    var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
    if (!methodInfo.Name.StartsWith("Get"))
      Log("In Dynamic Proxy - After executing '{0}' ",
        methodCall.MethodName);
      return new ReturnMessage(result, null, 0,
       methodCall.LogicalCallContext, methodCall);
  }
  catch (Exception e)
  {
    if (!methodInfo.Name.StartsWith("Get"))
      Log(string.Format(
        "In Dynamic Proxy- Exception {0} executing '{1}'", e),
        methodCall.MethodName);
      return new ReturnMessage(e, methodCall);
  }
}

 

在上面的代码里,有3处是代码重复的,methodInfo.Name.StartsWith("Get"),对于代码重复的,我们可以提取为方法,提取后的代码如下:

 

private static bool IsValidMethod(MethodInfo methodInfo)
{   return !methodInfo.Name.StartsWith("Get");
}

现在你只需要修改一个地方,但是你还是的修改类的代码,假如有一天,你的项目里需要自定过滤条件,此时最好的方法就是将Filter

定义为属性供用户自己来出来,所以这个需求的代码 现在修改为如下:

 

class DynamicProxy<T> : RealProxy
{   private readonly T _decorated;   private Predicate<MethodInfo> _filter;   public DynamicProxy(T decorated)     : base(typeof(T))   {     _decorated = decorated;     _filter = m => true;   }   public Predicate<MethodInfo> Filter   {     get { return _filter; }     set     {       if (value == null)         _filter = m => true;       else         _filter = value;     }   }   private void Log(string msg, object arg = null)   {     Console.ForegroundColor = ConsoleColor.Red;     Console.WriteLine(msg, arg);     Console.ResetColor();   }   public override IMessage Invoke(IMessage msg)   {     var methodCall = msg as IMethodCallMessage;     var methodInfo = methodCall.MethodBase as MethodInfo;     if (_filter(methodInfo))       Log("In Dynamic Proxy - Before executing '{0}'",         methodCall.MethodName);     try     {       var result = methodInfo.Invoke(_decorated, methodCall.InArgs);       if (_filter(methodInfo))         Log("In Dynamic Proxy - After executing '{0}' ",           methodCall.MethodName);         return new ReturnMessage(result, null, 0,           methodCall.LogicalCallContext, methodCall);     }     catch (Exception e)     {       if (_filter(methodInfo))         Log(string.Format(           "In Dynamic Proxy- Exception {0} executing '{1}'", e),           methodCall.MethodName);       return new ReturnMessage(e, methodCall);     }   }
}

 

 

基于这样,用户就可以自定义 那些方法需要AOP 那些方法不需要。 例如:

 

public class RepositoryFactory
{   public static IRepository<T> Create<T>()   {     var repository = new Repository<T>();     var dynamicProxy = new DynamicProxy<IRepository<T>>(repository)     {       Filter = m => !m.Name.StartsWith("Get")       };       return dynamicProxy.GetTransparentProxy() as IRepository<T>;     }     }
}

 

运行后的代码如下图:

 

Get 开头的方法就没记录日志。

此外,如果你不想更改 业务类,你更改AOP 类,代码如下:

 

class DynamicProxy<T> : RealProxy
{   private readonly T _decorated;   private Predicate<MethodInfo> _filter;   public event EventHandler<IMethodCallMessage> BeforeExecute;   public event EventHandler<IMethodCallMessage> AfterExecute;   public event EventHandler<IMethodCallMessage> ErrorExecuting;   public DynamicProxy(T decorated)     : base(typeof(T))   {     _decorated = decorated;     Filter = m => true;   }   public Predicate<MethodInfo> Filter   {     get { return _filter; }     set     {       if (value == null)         _filter = m => true;       else         _filter = value;     }   }   private void OnBeforeExecute(IMethodCallMessage methodCall)   {     if (BeforeExecute != null)     {       var methodInfo = methodCall.MethodBase as MethodInfo;       if (_filter(methodInfo))         BeforeExecute(this, methodCall);     }   }   private void OnAfterExecute(IMethodCallMessage methodCall)   {     if (AfterExecute != null)     {       var methodInfo = methodCall.MethodBase as MethodInfo;       if (_filter(methodInfo))         AfterExecute(this, methodCall);     }   }   private void OnErrorExecuting(IMethodCallMessage methodCall)   {     if (ErrorExecuting != null)     {       var methodInfo = methodCall.MethodBase as MethodInfo;       if (_filter(methodInfo))         ErrorExecuting(this, methodCall);     }   }   public override IMessage Invoke(IMessage msg)   {     var methodCall = msg as IMethodCallMessage;     var methodInfo = methodCall.MethodBase as MethodInfo;     OnBeforeExecute(methodCall);     try     {       var result = methodInfo.Invoke(_decorated, methodCall.InArgs);       OnAfterExecute(methodCall);       return new ReturnMessage(         result, null, 0, methodCall.LogicalCallContext, methodCall);     }     catch (Exception e)     {       OnErrorExecuting(methodCall);       return new ReturnMessage(e, methodCall);     }   }
}

 

 

 

上面定义了3 事件,分别是 BeforeExecute, AfterExecute and ErrorExecuting ,他们分别被调用 OnBeforeExecute, OnAfterExecute and OnErrorExecuting

其他 OnBeforeExecute, OnAfterExecute and OnErrorExecuting 会验证,如果存在事件处理函数,并且进行了方法过滤,他们就会被调用。所以一个设置事件的Repository Factory  定义如下:

 

public class RepositoryFactory
{   private static void Log(string msg, object arg = null)   {     Console.ForegroundColor = ConsoleColor.Red;     Console.WriteLine(msg, arg);     Console.ResetColor();   }   public static IRepository<T> Create<T>()   {     var repository = new Repository<T>();     var dynamicProxy = new DynamicProxy<IRepository<T>>(repository);     dynamicProxy.BeforeExecute += (s, e) => Log(       "Before executing '{0}'", e.MethodName);     dynamicProxy.AfterExecute += (s, e) => Log(       "After executing '{0}'", e.MethodName);     dynamicProxy.ErrorExecuting += (s, e) => Log(       "Error executing '{0}'", e.MethodName);     dynamicProxy.Filter = m => !m.Name.StartsWith("Get");     return dynamicProxy.GetTransparentProxy() as IRepository<T>;   }
}

 

到此,你现在可以选择在程序执行之前,执行之后,或者发生错误时,是否应用到AOP。
 
 
不是替代工具

使用AOP可以增加Code到应用贷程序的所有层,且没有重复的代码。我展示的例子至少通过一个基于装饰者模式的普通代理类应用一个拥有事件和表达式过滤器的AOP到你的类。

如您所见,RealProxy类是一个灵活的类,你可以完全控制代码,没有外部依赖。然而,请注意,RealProxy不可能替代其他AOP工具,比如PostSharp。PostSharp使用一个完全不同的方法。将中间语言(IL)代码post-compilation一步,而不是使用反射,所以它比RealProxy应该有更好的性能。相对于PostSharp, 你还必须做更多的工作来实现一个基于RealProxy。但是 PostSharp,您只需要创建方面类和一个属性添加到类(或方法),并且这就是所有。

另一方面,RealProxy,你可以l完全控制你的源代码,没有外部依赖项,您可以扩展和定制你想要的。例如,如果您想应用只在一个方面有日志属性的方法,你可以这样做:

 

 

public override IMessage Invoke(IMessage msg)

{

  var methodCall = msg as IMethodCallMessage;

  var methodInfo = methodCall.MethodBase as MethodInfo;

  if (!methodInfo.CustomAttributes

    .Any(a => a.AttributeType == typeof (LogAttribute)))

  {

    var result = methodInfo.Invoke(_decorated, methodCall.InArgs);

    return new ReturnMessage(result, null, 0,

      methodCall.LogicalCallContext, methodCall);

  }

    ...

除此之外,使用的技术RealProxy(拦截代码,允许程序来取代它)是强大的。例如,如果您想创建一个模拟框架,用于创建通用的模拟和测试的子类,您可以使用RealProxy类拦截所有调用,并将其替换为你自己的行为,但这另一篇文章的主题!

 

tks! 到此AOP 就告一段落了。

最新文章

  1. 省市县三级联动(jqurey+json)
  2. 极简MarkDown排版介绍(How to)
  3. 韩国手机游戏Elf Defense角色场景
  4. Unity Project Wizard (最近打开的项目记录)
  5. NetworkReachable学习笔记
  6. Altium Designer 使用小结
  7. Linux基本命令之逻辑测试一
  8. struts2基于Convention插件的约定映射使用
  9. VS2008下编译BOOST 1.39的ASIO库
  10. Java开发过程中开发工具Eclipse中导入jar包的过程
  11. 【模板】AC自动机(加强版)
  12. 紧急求助!配置SMTP插件出错,SMTP connect() failed
  13. linkin大话面向对象--抽象类
  14. 在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?
  15. JavaScript实现图片裁剪预览效果~(第一个小玩具)
  16. MVC 、JDBC、SQL、DBMS、RDBMS、DDL、DML、DCL
  17. bacula配置
  18. &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;的说明
  19. python实现测试报告的bug统计
  20. OpenStack高可用方案及配置

热门文章

  1. mac用ssh连接linux云服务器中文乱码或无法显示解决
  2. 20165332实验二 Java面向对象程序设计
  3. 阿里云上如何利用yum安装jenkins
  4. 配置Nginx作为反向代理服务器
  5. 三 web爬虫,scrapy模块介绍与使用
  6. HDU-1007-最小公共点对
  7. 百度之星2017初赛A-1006-度度熊的01世界
  8. 简短的perl程序
  9. 【第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛-J】 强迫症的序列
  10. js 复制粘贴功能记录