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

    1.官网 官网:http://www.jetbrains.com/idea/download/#section=windows 官方文档:http://www.jetbrains.com/help/i ...

  2. require.js资料

    1.http://www.ruanyifeng.com/blog/2012/11/require_js.html?bsh_bid=230697246 (require.js的用法) 2.http:// ...

  3. win8 商店应用 设计风格原则

    共八条: 1,突出内容(数据). a,仅在屏幕上保留最相关的元素:移除线条.框和不必要的图形效果:限制屏幕上持久显示的导航框,如选项卡. b,交互尽量直接在内容上,直接控制内容来完成操作,而不是使用控 ...

  4. 获取整个页面HTML的信息以及注意事项

    两种方式: 1.从每个节点获取 var a = '<!DOCTYPE html><html lang="zh-cn">'; var z = "&l ...

  5. 为什么这个地方用重定向会报错.只能用 服务器跳转?? 为什么我加了过滤器,还是能直接登陆 servlet

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, ...

  6. 一个css3 旋转效果 -- 待续

    <div class="container"> <div> <figure></figure> <figure>< ...

  7. 利用 localStorage 储存css js

    链接  版本号, 可以后台输出到jsp页面上 移动端webapp值得一试: 兼容性好 网速慢,LS读取+eval大多数情况下快于304 webapp不需要seo,css也可以缓存,再通过js加载 浏览 ...

  8. phpcms内容限制(转发自王小明爱红领巾)

    因为页面显示需要对文章内容做剪切,所以用到{str_cut($r[content],60)},但是出现了乱码 所以 {str_cut(strip_tags($r[content]),60)}加stri ...

  9. 《Drools7.0.0.Final规则引擎教程》第4章 4.3 定时器

    定时器 规则用基于 interval(间隔)和cron的定时器(timer),替代了被标注过时的duration 属性.timer属性的使用示例: timer ( int: <initial d ...

  10. Web应用程序与Web网站及部署在IIS中

    在Visual Studio可以创建 Web 应用程序项目或网站项目.通过选择 新建项目 或 打开项目 创建或打开一个 Web 应用程序项目在Visual Studio 文件 菜单. 通过选择 新建网 ...