代码改变世界

AOP

2012-10-04 10:42  Zhuang miao  阅读(316)  评论(0编辑  收藏  举报

 

首先还是继承那篇文章说一下吧,先是两个特性类,一个特性类是用来打在方法上的,纯粹是用于标记一下这个方法需要调用AOP进行一些什么操作:

另一个是打在类上头的,注意这个有些不同了。。注意他继承了两个东西,叫做ContextAttribute和IContributeObjectSink,并且实现了IContributeObjectSink的GetObjectSink方法。

稍候我们会做出说明,接下来是MyAopHandler:

这个类里头实现了AOP的处理,包括执行方法前和执行方法后。他判断了进来的方法有没有打上我们刚刚开始的时候提到的那个标记,若打了那个标记,则做一些处理之后再调用,调用完后再做处理。

 

值得注意的是,函数调用实际上在这里当成了消息:

剩下的就是业务层了:

可以看到,仅仅就是打了两个方法的标记,并且继承了一个东西,ContextBoundObject ,剩下的调用也没有什么特别的东西:

实际上,如果你编译并且看看IL的话,你会发现,即使在IL中,也没有在调用的时候露出任何痕迹。就是和普通的方法调用一样。

那么什么东西改变了呢?

我们的目标代码的调用继承了ContextBoundObject,一个引用如下:

 驻留在上下文中并要绑定到上下文规则的对象称为上下文绑定对象。上下文是用于定义对象集合所驻留的环境的属性集或用法规则集。 当对象进入或离开上下文时,规则被强制。 非上下文绑定的对象称为灵活对象。

 

上下文在对象激活期间创建。新对象被放置到现有上下文或新的上下文中,后者是通过元数据类型中包含的特性创建的。 使用提供用法规则的 ContextAttribute 标记上下文绑定类。可以添加的上下文属性包括有关同步和事务的策略。

根据这个的说明,我们修改了这个类在执行过程中的上下文。

上下文是一个有序的属性序列,用于定义其中的对象所处的环境。 上下文是在对象的激活过程中创建的,这些对象被配置为要求某些自动服务,如同步、事务、实时 (JIT) 激活、安全性等。 多个对象可以存留在一个上下文内。

上下文用于把具有相似执行需求的对象组合在一起。上下文由一组属性组合而成,它用于截获工作:即从不同的上下文中访问上下文绑定对象(context-bound object)时,侦听器可以在调用到达对象之前进行截获工作,如线程同步、事务和安全管理。

 

派生自 MarshalByRefObjects的类被绑定在应用程序域中。在应用程序域外,访问对象时需要代理。派生自 ContextBoundObject(它又派生自 MarshalByRefObjects)的类被限制在上下文中。在上下文之外,访问对象时需要代理。

还有个东西,叫做对象上下文接收器(MSDN的描述似乎是“对象特定的侦听接收器”)

 

这实际上是Remoting中的内容,我们稍后会提到Remoting。大致上来说,不同上下文之间的调用,被看做是“消息”,这个“消息”传递使用对象上下文接收器(即MSDN描述的“对象特定的侦听接收器"),我们因而能定义自己的对象上下文接收器,来实现AOP,在方法调用前和调用后进行一些操作。

 

IContributeObjectSink 用于分配对象上下文侦听器,而ContextAttribute 类,按照MSDN的说法,提供 IContextAttribute 和 IContextProperty 接口的默认实现。(好吧,我不太清楚他在说什么……因为即使是《C#高级编程》里头,也没有对这些东西做详细描述)

 

总而言之,我们修改了上下文,从而修改了.net基础结构对”方法调用“的默认实现。新的方法调用需要经过消息封送的处理,而消息封送的处理的过程,需要一个对象上下文侦听器——而我们实现了这个”对象上下文侦听器“,从而有机会在进行方法调用之前和之后做一些处理。

 

在处理过程中,返回的类型是IMessage,若返回一个

new System.Runtime.Remoting.Messaging.ReturnMessage(new Exception(), call);

那么就会说在调用过程中出现了异常。若用如下代码返回:

return new MethodResponse(CallContext.GetHeaders(), call);

则调用结束,不会发生任何事情。但如何改为调用其他方法尚不明确。

 

我们额外说说Remoting吧。Remoting是用于调用远程(本地和其他机器上的)方法的一个东西,应用起来十分简单,但里头的水比较深……稍候我们会说说这些水深在哪里:

 

例如,我们写一个调用,要在远程机器上执行一项操作,我们先定义这个操作:

然后,我们公布这个操作,需要一个服务器端:

注意,不会挂起在这里——你需要额外用一个ReadLine挂起在这里,否则会退出。

 

服务器端只是新建了一个Channel,并且公布了我们的Hello类。

 

然后,在客户端,我们注册一个管道,并且同样的,注册这个所谓的”知名类型“

 

我们有了一个Hello类型的obj——如果顺利,这个时候你可以在服务器上看到构造函数被调用了。如果不顺利,obj会为null。

 

接下来,调用obj的Greeting,这个时候,我们会发现服务器端上头会出现Greeting called字样,而客户端会返回Greeting xxx。一切都如同本地调用。

 

也可以用接口,不用将所有的具体实现给客户端。但是接口不能用new直接新建,而是要调用Activator.GetObject函数——这个时候就不需要用RegisterActivatedClientType了:

obj也可能为空。

 

看起来非常简单,但实际上,虽然IL代码中没有,但是dotnet基础架构中为我们做了很多操作,而且这些操作都是可替换的……这让人非常纠结。我们以这堆让人头昏脑涨的东西结束这篇博文。有兴趣的朋友可以找相关的资料进行下一步的研究。

 

以下内容来自《C#高级编程》的附录部分

 

这里有两张图:

上面是客户端的操作

下面是服务器的操作。

 

一些术语的说明:

   远程对象——远程对象是运行在服务器上的对象。客户端不能直接调用远程对象上的方法,

而要使用代理。使用.NET,很容易把远程对象和本地对象区分开:即任何派生自

MarshalByRefObject的类从来都不会离开它的应用程序域。客户端可以通过代理调用远程对

象的方法。

   信道——信道用于客户端和服务器之间的通信。信道包括客户端的信道部分和服务器的信

道部分。.NET Framework 4 提供了 3 种信道类型,它们分别通过TCP 、HTTP和IPC 进行

通信。此外,还可以创建自定义信道,这些信道使用其他协议通信。  

   消息——消息被发送到信道中。消息是为客户端和服务器之间的通信而创建的。消息包含

远程对象的信息、被调用方法的名称以及所有的参数。

   格式化程序——格式化程序用于定义消息如何传输到信道中。.NET 4 SOAP 格式化程序

和二进制格式化程序。使用 SOAP 格式化程序可以与不是基于.NET Framework 的Web 服务

通信。二进制格式化程序速度更快,可以有效地用在内部网环境中。当然,也可以创建自

定义格式化程序。

   格式化程序提供程序——格式化程序提供程序用于把格式化程序与信道关联起来。通过创

建信道,可以指定要使用的格式化程序提供程序,格式化程序提供程序则定义把数据传输

到信道中时所使用的格式化程序。

   代理——客户端调用代理的方法,而不是远程对象的方法。代理分为两种:透明的代理和

真实的代理。对于客户端,透明代理看起来与远程对象类似。在透明代理上,客户端可以

调用远程对象实现的方法。然后,透明代理调用真实代理上的Invoke()方法。Invoke()方法使

用消息接收器把消息传递给信道。

   消息接收器——消息接收器是一个侦听器(interceptor) 对象,简称接收器。在客户端和服务器

上都有侦听器。接收器与信道相关联。真实的代理使用消息接收器把消息传递到信道中,因

此,在消息进入信道之前,接收器可以进行截获工作。根据接收器所处的位置,可以把接收

器称为特使接收器(envoy sink) 、服务器上下文接收器、对象上下文接收器等。

   激活器——客户端可以使用激活器在服务器上创建远程对象,或者获取一个被服务器激活

的对象的代理。

   RemotingConfiguration 类——该类是用于配置远程服务器和客户端的一个实用程序类。它

可以用于读取配置文件或动态地配置远程对象。

   ChannelServices类——该类是一个实用程序类,可用于注册信道并把消息分配到信道中。

 

   信道接收来自客户端的已格式化消息,并且使用格式化程序打乱消息中的SOAP 或二进制

数据。然后,信道调用服务器上下文接收器。

   服务器上下文接收器是一个接收器链,链中的最后一个接收器继续调用对象上下文接收器

链。

   最后一个对象上下文接收器调用远程对象上的方法。

 

实际上,上下文也有很多术语,表明是一个管道:

 

   默认上下文——在创建应用程序域的同时,会在该应用程序域中创建默认上下文。如果实

例化的新对象需要不同的上下文特性,则系统会为它创建新的上下文。

   上下文特性——上下文特性可以赋予派生自 ContextBoundObject 的类。实现IContextAttribute

接口,可以创建自定义特性类。.NET Framework 在System.Runtime.Remoting.Contexts 名称空

间中有一个上下文特性类SynchronizationAttribute。

   上下文属性——上下文特性定义对象需要的上下文属性。上下文属性类实现 IContextProperty

接口。活动属性为主调链提供消息接收器。ContextAttribute 类实现IContextProperty 和

IcontextAttribute 接口,可以用作自定义属性的基类。

   消息接收器——消息接收器是方法调用的侦听器。使用消息接收器,可以截获方法调用。

特性可以提供消息接收器。