上一节实现了动态代理,接下来 有时候,我不需要在每一个方法都要记录日志,做权限验证 等等。 所有就有了这样的需求。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 就告一段落了。

动态代理AOP实现方法过滤的更多相关文章

  1. 浅析DispatchProxy动态代理AOP

    浅析DispatchProxy动态代理AOP(代码源码) 最近学习了一段时间Java,了解到Java实现动态代理AOP主要分为两种方式JDK.CGLIB,我之前使用NET实现AOP切面编程,会用Fil ...

  2. 动态代理案例1:运用Proxy动态代理来增强方法

    动态代理案例1: /*要求:运用Proxy动态代理来增强方法 题目:    1.定义接口Fruit,其中有addFruit方法    2.定义实现类FruitImpl,实现Fruit接口    3.定 ...

  3. spring aop 动态代理批量调用方法实例

    今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候 ...

  4. Java动态代理的实现方法

    AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执 ...

  5. 动态代理 aop切面实现事务管理

    1.定义接口和实现 public interface UserService { public String getName(int id); public Integer getAge(int id ...

  6. java动态代理——字段和方法字节码的基础结构及Proxy源码分析三

    前文地址:https://www.cnblogs.com/tera/p/13280547.html 本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的 ...

  7. 5.动态代理AOP实现-DynamicProxy模式

    通过动态代理模式Interceptor实现在RegUser()方法本身业务前后加上一些自己的功能,如:PreProceed和PostProceed,即不修改UserProcessor类又能增加新功能 ...

  8. spring中使用动态代理(AOP)

    spring是整合了BGLIB和JDK两种动态代理 示例:使用CGLIB代理 public class MyCar { private String color = "blue"; ...

  9. Spring-Boot的动态代理AOP原理

    前言 Spring AOP使用了动态代理技术,动态代理在业界比较流行的实现方式有,CGLIB,Javassist,ASM等等. Spring动态代理实现方式 Spring采用了JDK和CGLIB两种方 ...

随机推荐

  1. SQL命令查询Oracle存储过程信息(代码内容等)

    SELECT * FROM ALL_SOURCE  where TYPE='PROCEDURE'  AND TEXT LIKE '%0997500%'; --查询ALL_SOURCE中,(脚本代码)内 ...

  2. WPF 通过 CommandParameter 传递当前窗体到 ViewModel

    在应用 Command 模式中,需要在View上点击 一个按钮,需要将当前窗体作为参数传递为 command 两种方式传递当前窗体1.通过窗体名称(假设窗体名称为 ThisWindow)   < ...

  3. Django进阶Template篇001 - 常用模板标签及过滤器

    一.模板的组成 HTML代码+逻辑控制代码 二.逻辑控制代码的组成 1.变量(使用双大括号来引用变量) {{ var_name }} 2.标签(tag)的使用(使用大括号和百分号的组成来表示使用tag ...

  4. python中zip()函数的用法

    一. 定义 zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少内存 如果各个迭代器的元素个数不一致,则返回列表长度与最 ...

  5. 【PAT-L2-020】功夫传人

    链接:https://www.patest.cn/contests/gplt/L2-020 一门武功能否传承久远并被发扬光大,是要看缘分的.一般来说,师傅传授给徒弟的武功总要打个折扣,于是越往后传,弟 ...

  6. 【2018年全国多校算法寒假训练营练习比赛(第五场)-E】情人节的电灯泡(二维树状数组单点更新+区间查询)

    试题链接:https://www.nowcoder.com/acm/contest/77/E 题目描述 情人节到了,小芳和小明手牵手,打算过一个完美的情人节,但是小刚偏偏也来了,当了一个明晃晃的电灯泡 ...

  7. SqlServer表死锁的解决方法

    SqlServer表死锁的解决方法   前些天写一个存储过程,存储过程中使用了事务,后来我把一些代码注释掉来进行调试找错,突然发现一张表被锁住了,原来是创建事务的代码忘记注释掉.本文表锁住了的解决方法 ...

  8. UI- 不易记知识点汇总

    1.static: 所有的全局变量都是静态变量,而局部变量只有定义时加上类型修饰符static,才为局部静态变量. 静态变量并不是说其就不能改变值,不能改变值的量叫常量. 其拥有的值是可变的 ,而且它 ...

  9. 使用RateLimiter完成简单的大流量限流,抢购秒杀限流

    RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率. 通常可应用于抢购限流防止冲垮系统:限制某接口.服务单位时 ...

  10. 正则 去除html标签

    String.prototype.stripHtml=function(){ var re=/<(?:.)*?>/g; // *? 意味着匹配任意数量的重复 return this.rep ...