动态代理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两种方 ...
随机推荐
- python中sorted()函数的用法
一. 定义 sorted()函数对所有可迭代的对象进行排序操作 二. 语法 sorted(iterable [, key[, reverse]]]) iterable:可迭代对象 key:主要是用来进 ...
- [转载]java在线比较两个word文件
一.项目背景 开发文档管理系统或OA办公系统的时候,实现在线处理word文档的功能比较容易,但是也经常会有客户提出文档版本管理的需求,这就需要同时在线打开两个word文件,对比两个不同版本的word文 ...
- 016对象——__set __get get_class_methods get_class_vars
<?php /** */ //http://phpbasic.com/004object/16.php?type=admin /*session_start(); $_SESSION['utyp ...
- LeetCode OJ:First Missing Positive (第一个丢失的正数)
在leetCode上做的第一个难度是hard的题,题目如下: Given an unsorted integer array, find the first missing positive inte ...
- css3: scrollLeft,scrollWidth,clientWidth,offsetWidth 的区别
(需要提一下:CSS中的margin属性,与clientWidth.offsetWidth.clientHeight.offsetHeight均无关) offsetwidth:是元素相对父元素的偏移宽 ...
- <tf-idf + 余弦相似度> 计算文章的相似度
背景知识: (1)tf-idf 按照词TF-IDF值来衡量该词在该文档中的重要性的指导思想:如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性,正是我们所需要的关键词. ...
- 人生苦短之我用Python篇(遍历、函数、类)
#遍历 info = {'key1':'value1','key2':'value2','key3':'value3'} #方式一 for i in info: print(i,info[i]) #方 ...
- RIP 知识要点
RIP知识要点: UDP:520 版本:v1(广播包更新) / v2(组播更新 224.0.0.9 ) 度量值:跳数(最多跳15跳,路由为16跳时路由不可达) =================== ...
- kalman 滤波 演示与opencv代码
在机器视觉中追踪时常会用到预测算法,kalman是你一定知道的.它可以用来预测各种状态,比如说位置,速度等.关于它的理论有很多很好的文献可以参考.opencv给出了kalman filter的一个实现 ...
- Django之 中间件
中间件 介绍 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.如果你想修改请求,例如被传送到view中的Http ...