zoukankan      html  css  js  c++  java
  • 用动态代理实现AOP

    Summary        这篇文章介绍了Castle的动态代理是如何实现 AOP 的。

            向来我是“拿来主义”,即只管拿来用,不管正在用的东西是怎么实现的。最近由于一直想把 AOP 以及 IoC 等技术加入到项目中,因此对这些技术相当关注。后来选择了CastleProject中的DynamicProxy作为关注对象。不过这次起了贪心,不想再只知道使用,不知道如何实现了,于是开始深入去查看Castle是如何实现 AOP 的。


            Proxy 是实现 AOP 的途径之一,通过代理可以有效的拦截某个类方法的执行过程。


            从Castle中的测试例子可以看出,Castle使用了动态代码生成来对需要拦截的类生成一个代理,从而达到织入的目的。但是Castle是如何织入的呢?我打算使用一个简单的例子来测试Castle动态生成的代码。


    Scene        我设想了一个例子,一个类有一个方法:DoSomething,这个方法调用时输出Yes, * is running DoSomething,其中 * 表示类的名称。然后我需要在这个类调用DoSomething之前及之后,还需要输出Now i'm starting DoSomething以及 Now i'm ending DoSomething。当然,有很多方法可以实现,由于Castle是使用代理,所以我这里只使用代理。

            对于传统的代理模式,可以得出如下的类图:


    图1




            上图的类的代码分别如下:


    图2:类A的代码




    图3:类RealANoVirtual的代码




    图4:类ProxyClass的代码



            然后,在使用这些时,可以如下编写代码:


    图5:运行代码




            运行上面的代码,我们就可以特出如下的结果:


    图6:运行结果




            通过代理,可以透明的使用DoSomething方法。


            那么很显然,Castle也需要生成这样一个代理类,从而能够在调用DoSomething之前调用用户指定的代码。因此Castle提供了DynamicProxy以及Interceptor来达到目的。其中DynamicProxy会生成一个代理类,代理DoSomething操作,而在代理DoSomething操作时,使用用户指定的Interceptor达到拦截操作的目的。


            为了看到Castle生成的动态代理是怎么样的,我写了一个类:RealA,代码如下:


    图7:RealA代码




            RealA中只有一个方法,DoSomething。我需要在DoSomething操作前后达到与前面的传统的模式一样的效果,按照Castle的要求,我需要写一个Interceptor,从而能够拦截前后的操作,代码如下:


    图8:Interceptor代码




            暂时不去考虑ProxyInterceptor是怎么一回事,继续往下。


            有了需要拦截的类与Interceptor,那么直接就可以使用了,如下的代码:


    图9:运行代码




    图10:运行的结果




            Bingle!!!,成功了。


            那么Castle究竟做了什么呢?


            在运行时,Castle会生成一个Assembly,放在应用的运行目录下,名称为:GeneratedAssembly.dll。通过反编译这个Assembly,就可以看到Castle究竟做了什么。


            为了更好的说明,我把反编译后的代码分段说明:


    1、Castle生成了一个代理类CProxyTypeRealA0,代理类继承自RealA:


    public class CProxyTypeRealA0 : RealA


    {


    ...


    }


    2、在CProxyTypeRealA0类中如下定义了一些Field:


    图11:Field定义




            其中的delegate的定义如下:


    图12:delegate的定义




            那么,这些Delegate的目的是什么呢?通过CProxyTypeRealA0的构造函数中的代码可以看出用途:


    图13:构造函数




            这里,我们关注的是DoSomething。从上面的构造函数代码可以看出,delegate指向了callback__DoSomething这个回调函数,这个函数的代码如下:


    图14:回调函数代码




            在这个回调函数中,就直接调用了RealA的DoSomething方法。


            那么,Castle是如何调用到RealA的DoSomething的方法的呢?


    3、调用链


            在CProxyTypeRealA0中,覆盖了RealA的DoSomething方法,如下:


    图15:覆盖的DoSomething




            从代码中可以看出,DoSomething中调用了本地方法_Method2Invocation获取一个Invocation,然后调用Interceptor执行一些动作。


            仔细看,在_Method2Invocation调用时传入了一个参数this.cached1,这个参数是一个delegate对象,并且在构造函数中指向了回调函数callback_DoSomething。这是一个很关键的地方,因此我们有必要看看_Method2Invocation作了什么。


    图16 Method2Invocation的代码




            Method2Invocation方法中,创建/获取了一个MethodInfo对应的Invocation,而Invocation封装了传入的delegate等相关信息。


            很显然,封装这些信息是为了更好的传递。从Method2Invocation出来,接下去就是调用在构造函数中传入的Interceptor。


            Interceptor的Intercept方法需要两个参数,一个就是前面封装好的Invocation对象,另一个是一个参数数组。目前看不出这个参数数组有什么用。


            那么Intercept方法作了什么


            看看Interceptor的实现代码,我的例子中的Interceptor直接继承自StandardInterceptor,所以先看看StandardInterceptor的代码:


    图17 StandardInterceptor的代码




            从代码中可以看出,这是一个模板模式。分别调用了PreProcess,PostProcess方法。这样就可以调用了我覆盖的两个方法。但是,在这里依然没有看到调用了DoSomething方法,别急,代码中调用了传入的Invocaion对象的Process方法。那么这个方法作了什么?


            由于在Method2Invocation中,创建的是SameClassInvocation对象,因此,直接看SameClassInvocation的代码:


    图18 SameClassInvocation的代码




            Bingle!!! Process方法调用了传入的delegate对象,这样就调用到了回调函数callback_DoSomething,而回调函数又调用了RealA的DoSomething方法。这样,一个完整的拦截过程就实现了。同时,这里也看到前面的参数数组就是DoSomething的参数数组,只不过例子中没有参数,所以为零了。


            至此,我们看到了Castle完成代码织入的整个过程:


            首先通过代码生成完成一个代理类,该代理类继承自要织入的类。然后在代理类中覆盖要拦截的方法,并在覆盖的方法中封装Invocation对象,并传给用户传入的Intercepter对象的Intercept方法。在Intercept方法依次调用Intercepter的PreProcess,通过Invocation传入的Delegate指向的回调函数,Intercepter的PostProcess方法,从而达到拦截的目的。


    下面是例子的代码下载:


    例子下载


    示例在Snippet Comiler 2.0 中编译运行通过。编译时需要自行添加对Castle.DynamicProxy.dll的引用。


    如果在VS.NET中运行,需要自己创建Project,并加入压缩包中的文件。


  • 相关阅读:
    PHP 使用 GET 传递数组变量
    Java实现 蓝桥杯 算法训练 数据交换
    Java实现 蓝桥杯 算法训练 数据交换
    Java实现 蓝桥杯 算法训练 数据交换
    Java实现 蓝桥杯 算法训练 景点游览
    Java实现 蓝桥杯 算法训练 景点游览
    Java实现 蓝桥杯 算法训练 景点游览
    Java实现 蓝桥杯 算法训练 二进制数数
    Java实现 蓝桥杯 算法训练 二进制数数
    Java实现 蓝桥杯 算法训练 二进制数数
  • 原文地址:https://www.cnblogs.com/iaxes/p/132868.html
Copyright © 2011-2022 走看看