动态代理AOP实现方法过滤
上一节实现了动态代理,接下来 有时候,我不需要在每一个方法都要记录日志,做权限验证 等等。 所有就有了这样的需求。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实现方法过滤的更多相关文章
- 浅析DispatchProxy动态代理AOP
浅析DispatchProxy动态代理AOP(代码源码) 最近学习了一段时间Java,了解到Java实现动态代理AOP主要分为两种方式JDK.CGLIB,我之前使用NET实现AOP切面编程,会用Fil ...
- 动态代理案例1:运用Proxy动态代理来增强方法
动态代理案例1: /*要求:运用Proxy动态代理来增强方法 题目: 1.定义接口Fruit,其中有addFruit方法 2.定义实现类FruitImpl,实现Fruit接口 3.定 ...
- spring aop 动态代理批量调用方法实例
今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候 ...
- Java动态代理的实现方法
AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执 ...
- 动态代理 aop切面实现事务管理
1.定义接口和实现 public interface UserService { public String getName(int id); public Integer getAge(int id ...
- java动态代理——字段和方法字节码的基础结构及Proxy源码分析三
前文地址:https://www.cnblogs.com/tera/p/13280547.html 本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的 ...
- 5.动态代理AOP实现-DynamicProxy模式
通过动态代理模式Interceptor实现在RegUser()方法本身业务前后加上一些自己的功能,如:PreProceed和PostProceed,即不修改UserProcessor类又能增加新功能 ...
- spring中使用动态代理(AOP)
spring是整合了BGLIB和JDK两种动态代理 示例:使用CGLIB代理 public class MyCar { private String color = "blue"; ...
- Spring-Boot的动态代理AOP原理
前言 Spring AOP使用了动态代理技术,动态代理在业界比较流行的实现方式有,CGLIB,Javassist,ASM等等. Spring动态代理实现方式 Spring采用了JDK和CGLIB两种方 ...
随机推荐
- Ubuntu chrome FQ
按照文档FQ,需要注意一下两点: 1. 在安装Chrome 下的 SwitchyOmega 插件时,拖入到浏览器不能识别,应该打开chrome://extensions/再拖入: 2.在设置时排列列表 ...
- Autolayout .Compact or .Regular [iPhone/iPad]
- ARM汇编指令集1
(汇编)指令是CPU机器指令的助记符,经过编译过会得到一串0011组成的机器码,可以由CPU读取执行. (汇编)伪指令本质不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译 ...
- Mac os x 下配置Intellij IDEA + Tomcat 出现权限问题的解决办法
出现的错误提示如下: 下午9:11:27 All files are up-to-date下午9:11:27 All files are up-to-date下午9:11:27 Error runni ...
- R语言:数据的分割-计算-整合(split-apply-aggregate)
当获取到原始数据时,我们通常的做法是对该数据进行分割成小片段,然后对各小片段进行计算统计,最后整合成最终的数据.这是统计学里数据处理的一般规律. R语言为我们提供了相应的函数来分别处理这三个阶段任务. ...
- Freemarker Failed at: ${itm.creatTimeString?string("yyyy-MM... [in template
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px 'Helvetica Neue'; color: #454545} p.p2 {margin: ...
- tf随笔-5
# -*- coding: utf-8 -*-import tensorflow as tfw1=tf.Variable(tf.random_normal([2,6],stddev=1))w2=tf. ...
- React Native组件(一)组件的生命周期
相关文章 React Native探索系列 前言 React Native有很多组件比如Image.ListView等等,想要合理的使用组件,首先要先了解组件的生命周期. 1.概述 无论你是开发And ...
- android知识点大总结
1.掌握Android编程的基本概念与要点,Android SDK及其开发环境搭建.Android项目结构分析.2.Android 应用设计模式.文件系统.3.文件形式的数据存储与访问.SDCard卡 ...
- HDU2032 杨辉三角
解题思路:不要小看这题水题,如果数据类型没有用long long, 当n开为35时,会出现TLE,而且会报非法内存访问,现在还 不理解为什么,若有高手,请不吝赐教. 上代码: #include< ...