技术开发 频道

Remoting基本原理及其扩展机制(中)

    Pipeline

    Pipeline是何物?我们并没有解释清楚这个概念,是否存在一个对象它就叫Pipeline或者类似的名字?遗憾地告诉你,没有!可以说这里的Pipeline是一个抽象的概念,它表示了当我们调用一个远程对象时从RealProxy到StackBuildSink之间所经过的一系列Sink的集合,但是并不存在一个单独的链表把这些Sink全部链接起来。也就是说并不存在一个大的Sink链表,当你触发远程方法后,我们就依次从这个链表中取出一个个的Sink,大家挨个处理一下消息。不过在远程对象的代理中倒是维护了一个由ChannelSink组成的链表。不过需要注意它并不代表整个Pipeline,而只能算是其中一部分,在后面我们会看到Pipeline中还包括了很多其他类型的Sink。这个链表保存在RealProxy的_identity对象中,链表是通过IClientChannelSink的Next属性链接起来的,在_identity对象中保存链表的第一个元素,其他元素可以通过Next属性获得,如下图所示:

    下面我们来看看这个链表是如何得到的。每当我们通过TransparentProxy调用远程方法时,如下图所示,最终会调用到RemotingProxy中的InternalInvoke方法,它将负责把各个ChannelSink创建出来并链接在一起。

internal virtual IMessage InternalInvoke(IMethodCallMessage reqMcmMsg, bool useDispatchMessage, int callType) { //... if (identity.ChannelSink == null) { IMessageSink envoySink = null; IMessageSink channelSink = null; if (!identity.ObjectRef.IsObjRefLite()) { RemotingServices.CreateEnvoyAndChannelSinks(null,identity.ObjectRef, out envoySink , out channelSink ); } else { RemotingServices.CreateEnvoyAndChannelSinks(identity.ObjURI, null, out envoySink , out channelSink ); } RemotingServices.SetEnvoyAndChannelSinks(identity, envoySink,channelSink ); if (identity.ChannelSink == null) { throw new RemotingException("...")); } } //... } //代码 3

    第一个判断语句(Line 5)说明创建并链接ChannelSink的工作只发生在第一次调用,以后的每次调用将重复使用第一次的结果。第二个判断语句(Line 9)暂且不管,我只需知道在下一步将创建出两个Sink链,一个是EnvoySinl链,而另一个是ChannelSink链,前者我们也先不去管它(将在下部中介绍)而后者将通过out关键字传给局部变量channelSink。其中CreateEnvoyAndChannelSinks方法最终会把ChannelSink链的创建任务交给Channel对象,至于Channel对象是如何配合ChannelSinkProvider工作的,我们在上一篇文章中已经介绍过了。

 不知你有没有注意到局部变量channelSink(Line 8)此时的类型是IMessageSink 而不是IClientChannelSink。到关键地方了,大家提起精神啊!明明我们创建的是ChannelSink链却把头元素的类型设为IMessageSink 。这是为什么?大家知道在采用HttpChannel时,ChannelSink链的一个元素是什么吗?——SoapClientFormatterSink。你认为它应该是一个Message Sink还是Channel Sink?它是负责将消息对象格式为数据流的,操作对象是原始消息,自然应该是一个MessageSink。呵呵,原来搞了半天Remoting本身就有一个利用IClientChannelSinkProvider扩展MessageSink的例子(你可以在类库中找到SoapClientFormatterSinkProvider)。如之前所述,SoapClientFormatterSink虽然是一个MessageSink,但是为了利用IClientChannelSinkProvider将其插入到Pipeline中,它也不得不实现IClientChannelSink接口,而且你可以看到它在实现IClientChannelSink接口中的方法时,全部抛出异常。如下所示:

public class SoapClientFormatterSink :IMessageSink, IClientChannelSink//... { //... //Implement method in IMessageSink public IMessage SyncProcessMessage(IMessage msg) { IMethodCallMessage message1 = (IMethodCallMessage) msg; try { ITransportHeaders headers1; Stream stream1; Stream stream2; ITransportHeaders headers2; this.SerializeMessage(message1, out headers1, out stream1); this._nextSink.ProcessMessage(msg, headers1, stream1, out headers2, out stream2); if (headers2 == null) { throw new ArgumentNullException("returnHeaders"); } return this.DeserializeMessage(message1, headers2, stream2); } catch (Exception exception1) { return new ReturnMessage(exception1, message1); } catch { return new ReturnMessage(new Exception("...")), message1); } } //Implement method in IClientChannelSink public void ProcessMessage(...) { throw new NotSupportedException(); } //... } //代码 4
0
相关文章