AOP之拦截函数调用链实现

定义函数A,B,C,调用A->B->C,这样就形成了函数静态调用链,而AOP要做的是能动态的添加多个B,形成A->B1->B2->B3...->C这样的效果,在EntLib(MS的企业库)Unity中有这样的实现,不过要看明白里面的代码的确需要花不少脑子,3年前看过里面的代码并做了记录,但是这两天翻出来看时照样化了很大精力,并杀死杀伤大量脑细胞,于是痛下决心将整个过程整理并画出时序图。

测试代码:

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
BLLObj bll = new BLLObj();
InterceptionUtil util = new InterceptionUtil();
util.Pipeline.InterceptionBehaviors.Add(new BehaviorA() { Id = "1" });
util.Pipeline.InterceptionBehaviors.Add(new BehaviorA() { Id = "2" });
util.Pipeline.InterceptionBehaviors.Add(new BehaviorA() { Id = "3" }); var r = util.Call(bll, "Add", new object[] { 3, 4 });
Console.WriteLine("结果:" + r); Console.WriteLine(new string('-', 40)); var r1 = util.Call(bll, "Concat", new object[]{ new object[] { "a",1, "b", 2 }});
Console.WriteLine("结果:" + r1); Console.WriteLine(new string('-', 40)); var r2 = util.Call(bll, "DoSome", new object[] { });
Console.WriteLine("结果:" + r2);
}
} #region 测试业务类 public class BLLObj
{
public int Add(int a, int b)
{
Console.WriteLine("Add");
return a + b;
}
public string Concat(object[] args)
{
Console.WriteLine("Concat");
return string.Concat(args);
}
public void DoSome()
{
Console.WriteLine("DoSome");
} }
#endregion

(图1)函数链调用的效果图:

从图1可以看到,在目标对象的目标方法被调用前包裹了3层拦截类的函数调用,正是这样嵌套结构允许我们实现数据库事务控制,错误记录,权限控制,性能监测等一系列AOP应用.

实现代码

下面的代码涉及2个接口与5个类,话说人脑在同时考虑多个对象时会很受伤,所以俺在代码里加了必要的注释并在下面付上了调用序列图,请配合起来看。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection; namespace FuncLinkT2
{ //两个互相引用的接口,从定义的这一刻开始
//就注定了他们需要互相依靠,相伴一身.......
//当然哥们的纠结也从此开始
public interface IInterceptionBehavior
{
MethodReturn Invoke(MethodInvocation input, IGetNextInterceptionBehavior nb);
}
public interface IGetNextInterceptionBehavior
{
IInterceptionBehavior GetNext();
} /// <summary>
/// 作为IInterceptionBehavior.Invoke参数,
/// 便于拦截行为类获取当前拦截方法的信息
/// 包括被拦截对象与被拦截方法
/// </summary>
public class MethodInvocation
{
public MethodBase MethodBase { get; set; }
public object Target { get; set; } }
/// <summary>
/// 被拦截方法的返回结果包装
/// 同样便于拦截行为类获取方法调用后接返回结果
/// </summary>
public class MethodReturn
{
public object ReturnValue { get; set; }
public Exception Err { get; set; } } #region 一个拦截行为类的实现
public class BehaviorA : IInterceptionBehavior
{
public string Id { get; set; } public MethodReturn Invoke(MethodInvocation input, IGetNextInterceptionBehavior nb)
{ Console.WriteLine("Behavior:" + Id + "->Invoke Befor!"); IInterceptionBehavior behavior = nb.GetNext(); var r = behavior.Invoke(input, nb); Console.WriteLine("Behavior:" + Id + "-> invoke After!"); return r; }
}
#endregion /// <summary>
/// 实际对象调用代理类
/// 包装成IInterceptionBehavior以便加到BehaviorPipeline末尾
/// </summary>
public sealed class InterceptionInvocationProxy : IInterceptionBehavior
{
public object[] Args;
public MethodInvocation Invocation;
public object Target; public MethodReturn Invoke(MethodInvocation input, IGetNextInterceptionBehavior nb)
{
Console.WriteLine("InterceptionInvocationProxy->实际对象将被调用!");
var ret= new MethodReturn();
try
{
ret.ReturnValue = Invocation.MethodBase.Invoke(Target, Args);
}
catch (Exception ex)
{
ret.Err = ex; }
return ret; }
} public sealed class NextBehaviorsImp : IGetNextInterceptionBehavior
{
internal InterceptionBehaviorPipeline Pipeline;
internal int InterceptorIndex;
internal IInterceptionBehavior Target; public IInterceptionBehavior GetNext()
{
InterceptorIndex++;
if (InterceptorIndex < Pipeline.InterceptionBehaviors.Count)
{
IInterceptionBehavior local1 = Pipeline.InterceptionBehaviors[InterceptorIndex];
return local1;
}
return Target;
}
}
/// <summary>
/// 拦截行为链条
/// </summary>
public class InterceptionBehaviorPipeline
{
internal readonly List<IInterceptionBehavior> InterceptionBehaviors;
// Properties
public int Count
{
get
{
return InterceptionBehaviors.Count;
}
}
// Methods
public InterceptionBehaviorPipeline()
{
InterceptionBehaviors = new List<IInterceptionBehavior>();
}
public MethodReturn Call(MethodInvocation input, IInterceptionBehavior target)
{ //无任何拦截行为
if (InterceptionBehaviors.Count == 0)
{
return target.Invoke(input, null);
}
//至少有一个IInterceptionBehavior
NextBehaviorsImp nb = new NextBehaviorsImp();
nb.Target = target;
nb.Pipeline = this;
nb.InterceptorIndex = 0;
return InterceptionBehaviors[0].Invoke(input, nb); }
} public class InterceptionUtil
{
internal InterceptionBehaviorPipeline Pipeline = new InterceptionBehaviorPipeline(); public object Call(BLLObj targetObj, string methodName, object[] args)
{ InterceptionInvocationProxy proxy = new InterceptionInvocationProxy();
proxy.Target = targetObj;
proxy.Args = args;
proxy.Invocation = new MethodInvocation();
proxy.Invocation.MethodBase = proxy.Target.GetType().GetMethod(methodName);
proxy.Invocation.Target = proxy.Target; //将目标类的方法封装代理提供给调用连,开始进行拦截调用
MethodReturn ret= Pipeline.Call(proxy.Invocation, proxy);
return ret.ReturnValue; }
} }

(图2)调用序列--务必鼠标右键找到图片url后看大图

参考

1.当然实现函数调用链不一定要搞这么麻烦,可以通过嵌套代理类来实现上面的调用效果.
地址:http://www.cnblogs.com/wdfrog/p/3162524.html

2.如果哥们觉得上面的看起来很轻松,那么你可以直接看MS使用委托代替上面两个接口的实现代码.
地址:http://www.cnblogs.com/wdfrog/archive/2010/10/23/1859021.html

至于为什么微软要用委托(而且用了大量的匿名委托)来实现,估计是觉得用接口是java干的事情,为了跟其保持距离所以某个MS的程序员在领导的要求下写出了这样变态的代码。

 
 
 
标签: AOP函数调用链

AOP之拦截函数调用链实现的更多相关文章

  1. spring---aop(3)---Spring AOP的拦截器链

    写在前面 时间断断续续,这次写一点关于spring aop拦截器链的记载.至于如何获取spring的拦截器,前一篇博客已经写的很清楚(spring---aop(2)---Spring AOP的JDK动 ...

  2. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  3. 33、[源码]-AOP原理-获取拦截器链-MethodInterceptor

    33.[源码]-AOP原理-获取拦截器链-MethodInterceptor

  4. Spring异步调用原理及SpringAop拦截器链原理

    一.Spring异步调用底层原理 开启异步调用只需一个注解@EnableAsync @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTI ...

  5. JdkDynamicAopProxy 拦截器链的获得与递归执行

    JdkDynamicAopProxy类的invoke方法 1.获得拦截器链 List<Object> chain = this.advised.getInterceptorsAndDyna ...

  6. 手撸了一个HTTP框架:支持Sprng MVC、IOC、AOP,拦截器,配置文件读取...

    https://github.com/Snailclimb/jsoncat :仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架 距离上一次给小伙伴们汇报简易 ...

  7. java 动态代理—— Mybaties 拦截器链基本原理实现

    1.摘要 Mybaties 中有个分页插件,之前有特意的去了解了一下原理 :https://www.cnblogs.com/jonrain0625/p/11168247.html,从了解中得知分页插件 ...

  8. AOP实现拦截对象以及获取切入目标方法和注解

    AOP实现拦截对象以及获取切入目标方法和注解 一.JoinPoint是什么? AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用 o ...

  9. SIGSEGV异常时打印函数调用链

    C语言写的程序跑飞了,怎样打印出函数调用链呢? linux_dev_framework软件包中的trace_exception_test.c就是一个实现演示样例. 该程序有益产生一个内存訪问异常,然后 ...

随机推荐

  1. android详细信息java.util.ConcurrentModificationException变态

    在今天做android当项目,我遇到了这个异常,好吧.其实最不寻常遇到异常IllegalstateException.它们与我们的硬件连接SDK抛出,我想折磨学生阿玉啊.扯远了. 今天,我想回到这个异 ...

  2. MVC验证06-自定义错误信息

    原文:MVC验证06-自定义错误信息 本文体验自定义错误信息.   系统默认的错误信息 在"MVC验证02-自定义验证规则.邮件验证"中,我们自定义了一个验证Email的类.如果输 ...

  3. Asp.Net MVC5入门学习系列①

    原文:Asp.Net MVC5入门学习系列① 现在直接开始MVC5的学习系列,学习资源来自Micrsoft. 开始使用Asp.Net MVC 5 打开Visual Studio 2013,然后新建一个 ...

  4. [DevEpxress]GridControl 显示Gif动画

    原文:[DevEpxress]GridControl 显示Gif动画 如果没有对进行设置,那么GridControl列中gif在编辑状态下,才能显示动画效果,如果要设置列自动显示动画效果,可以进行如下 ...

  5. 大约xib连接错误bug正确

    今天code什么时候,发现xib除了加载问题,研究发现的一个问题 在连接的时候, object一定要选择,您连接view,代替 File's Owner 版权声明:本文博客原创文章,博客,未经同意,不 ...

  6. 快速构建Windows 8风格应用23-App Bar概述及使用规范

    原文:快速构建Windows 8风格应用23-App Bar概述及使用规范 本篇博文主要介绍App Bar概述.App Bar命令组织步骤.App Bar最佳实践.   App Bar概述 Windo ...

  7. codeforces #262 DIV2 C称号Present(二分法+贪婪)

    职务地址:http://codeforces.com/contest/460/problem/C 这个题是用二分枚举最小值.然后推断是否能在规定的次数内使得全部的数都达到这个值.推断的时候要用贪心的方 ...

  8. PE文件结构(五岁以下儿童)基地搬迁

    PE文件结构(五岁以下儿童) 參考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 基址重定位 链接器生成一个PE文件时,它会如果程序被装入时使用的默认ImageBase基地址(VC默认 ...

  9. weblogic生产、开发模式互转

    生产模式与开发模式转换: 1.生产模式-->开发模式     将%DOMAIN_HOME%\config\config.xml文件中<production-mode-enabled> ...

  10. 老调重弹--面向对象设计原则--GRASP设计原则

    GRASP概述 GRASP,全称General Responsibility Assignment Software Patterns,译为”通用职责分配软件原则“,包含以下原则和模式 控制器(Con ...