Ice框架提供了不少回调设施,其中一些是使用Ice远程调用进行ami模式或amd模式的支撑。本篇来看一下用于代理端的回调设施。

Ice代码中有好几个Callback相关命名的基类,并且slice还会为你描述的接口,每个接口方法生成好几个回调类,让人眼花缭乱。其实认真整理归纳一下,就会发现,为我们提供的代理调用回调接口只有两个,一个是较为底层一点的,你需要解释Future,另一个是较为高级一点的,框架为你解释好Future,并以输出参数回调。而回调的挂接点是在网络层的io读写完成事件。较为底层一点的回调接口有两个函数,分别是sent(const AsyncResultPtr&)和completed(const AsyncResultPtr&),这两个回调函数分别挂接在网络层的io写完成事件以及io读完成事件上。较为高级一点的回调接口,有sent,response和exception三个函数入口,底层的回调处理completed将读出的响应结果分类为exception或正常输出参数,分别递交给exception或response回调入口。它们的关系如下图:

OutgoingAsync是所有具体Future类的直接基类(,继承树最后一层基类),本身就是一个Callback类,挂接回调在网络层。当ConnectionI对网络io事件进行dispatch调度时,就会满足条件下相应回调OutgoingAsync。OutgoingAsync自身有一套回调框架,可以使回调同步在io执行dispatch调度的线程上,或异步执行在其它线程上。不论那种情况,Outgoing最后将回调委托在基类CallbackCompletion。CallbackCompletion再委托给上层提供的回调。通过回调离开Future层进入的是由Slice为我们生成的框架代码,这时使用的回调接口,才是我们上面说的较为底层的回调接口sent(const AsyncResultPtr&)和completed(const AsyncResultPtr&)。Future以参数方式委托给上层代码进行事件回调处理。这个委托我们是可以在创建一个Future进行指定的。我们有两种选择,一是提供较为底层的回调方式的委托,二是提供较为高级方式的版本。Slice为我们生成的5个begin_Method函数中,有两个是指定底层次版本回调,另两个是指定高级版本回调的,最一个是不使用回调的。我们看一下slice生成的begin_Method函数模板:

::Ice::AsyncResultPtr begin_Method(const ::Ice::Context& context = ::Ice::noExplicitContext);
::Ice::AsyncResultPtr begin_Method(const ::Ice::CallbackPtr& del, const ::Ice::LocalObjectPtr& cookie = );
::Ice::AsyncResultPtr begin_Method(const ::Ice::Context& context, const ::Ice::CallbackPtr& del, const ::Ice::LocalObjectPtr& cookie = );
::Ice::AsyncResultPtr begin_Method(const ::Test::Callback_MyClass_opOnewayPtr& del, const ::Ice::LocalObjectPtr& cookie = );
::Ice::AsyncResultPtr begin_Method(const ::Ice::Context& context, const ::Test::Callback_MyClass_opOnewayPtr& del, const ::Ice::LocalObjectPtr& cookie = );
::Ice::AsyncResultPtr _iceI_begin_Method(const ::Ice::Context&, const ::IceInternal::CallbackBasePtr& del, const ::Ice::LocalObjectPtr& cookie = , bool sync = false);

在每个函数的都有一个参数,类型为Callback相关,命名为del,其实就是delegate,我们提供的Callback是回调处理中的委托目标,而这个委托又会委托给我们自定义的Callback中去。

我们要如何使用代理端的远程调用的回调呢,请看下图:

红色的类,就是我们要提供给Ice的回调类,这里要注意的是,我们的自定义的回调类并不继承于任何一个Callback基类。因为我们自定义的回调类是蓝色的框架提供的回调类委托的目标,而蓝色的由框架提供的回调类,却是OutgoingAsync(基类为AsyncResult的Future)的回调委托目标。其实我们提供的回调类,到最后回调到达已经是第二层委托了。我们提供的回调类唯一要继承的就是Shared。蓝色的类就像一个Binder绑定我们的提供的回调类以及我们选择为这个回调的函数。蓝色类继承树上的子类实例是我们调用Slice为我们生成begin_Method需要传入的回调委托,它绑定我们自定义的回调类和我们选用作本次远程调用回调的函数。蓝色类的继承自CallbackBase,CallbackBase也定义了回调虚接口sent和completed,为什么我们自定义的回调不是直接继承这个有回调虚接口呢?原因是那样的话,我们的自定义的回调类就必然会很多,不利于我们维护。尽管Slice为我们生成了许多我们压根都不会使用到的类,但是我们是不用去维护这些类的。使用绑定(binder,绑定target和function selector)以及委托的方式,我们就可以方便开发出处理多种回调函数的回调类。我们的回调委托并不是固定绑定到某一个对象调用的上,而是只对应某一次对象调用,并且我们可以为每次对象调用选用自定义回调类的不同成员函数进行绑定回调处理。

我们的回调起源于网络服务层的io读写完成事件,经过AsyncResult(Future层)的回调框架最后委托到我们回调代码。那么AsyncResult(Future层)的回调框架又为我们做了些什么工作呢?首先总览AsyncResult的类图:

所有具体的Future类都多继承自两个基类CallbackCompletion和OutgoingAsync,可参考最下方同一水平层次的三个类。最顶层的基类有两员分别是,OutgoingAsyncCompletionCallback和AsyncResult,AsyncResult是一个提供给上层访问的接口,基本与回调框架无关。我们将无关的繁枝冗节去除,只留下回调框架相关的方法接口以及依赖关系,如下图:

白色的类是我们上面Future类图中的成员,并且借用OC对类(@interface)的分类声明,我们将一个类的方法按功能聚集成一个分类。

分类中的方法名与我们本篇开始提到的回调接口sent,response和exception相关。相关的方法有

sent,sentImpl,invokeSent,invokeSentAsync,handleSent, handleInvokeSent ;

response,responseImpl,invokeResponse,invokeResponseAsync,handleResponse,handleInvokeResponse ;

exception,exceptionImpl,invokeException,invokeExceptionAsync, handleException,handleInvokeException ;

这些函数的命名相当迷惑人,如果你不知道它们的真正作用又没有文档的话。sent,response和exception分别必须调用它们对应的(sent|response|exception)Impl版本,它们的Impl版本实质在调用它们各自对应的handle(Sent|Response|Exception)方法。但是这三组方法,根本不是回调处理,而只是三组查询方法,它们都返回一个bool值,表示是否支持回调。剩下的方法则都带invoke词根,但是它与AsyncResult的invoke并没有关系,而是真正要调用事件回调。invokeSent,invokeResponse和invokeException分别依赖调用handleInvokeSent,handleInvokeResponse和handleInvokeException,它们就是最后委托上层回调的地方。至于invokeSentAsync,invokeResponseAsync和invokeExceptionAsync则是将invokeSent,invokeResponse和invokeException方法委托给嵌套类,dispatch(和OC的GCD中语义一样)到线程池异步执行。invokeSent,invokeResponse和invokeException方法集是枢纽点,上面图用红字显示。当执行一次带回调需要的同步远程调用,就有一条最小的依赖路径,即上图中红色类和红字类,ConnectionI和OutgoingAsyncBase。网络服务层的Connection在调用io事件时,回调Future(OutgoingAsyncBase,which is a AsyncResult)的回调处理,再通过OutgoingAsyncCompletionCallback接口服务委托回调到上层。

ZeroC ICE的远程调用框架 Callback(一)-AMI异步方法调用框架的更多相关文章

  1. ZeroC ICE的远程调用框架 Slice如何帮助我们进行Ice异步编程(AMI,AMD)

    Slice最大的用处就是为我们使用Ice进行编程,代劳绝大部分的重复性代码,并提供一些帮助性的框架代码,如用于AMI和AMD方式进行异步编程的回调框架. 当Slice不为我们生成代码时,我们仍然可以按 ...

  2. ZeroC ICE的远程调用框架 AMD

    继上一篇<ZeroC ICE的远程调用框架>,本篇再来说其中的AMD.(本篇需要重写) 当在ice文件中声明某个接口方法Method为["amd"]后,接口方法在stu ...

  3. ZeroC ICE的远程调用框架

    想搞清楚slice为我们生成了什么样的框架代码,就先搞明白Ice的远程调用框架暗中为我们做了些什么? Ice将Ice Object的方法调用分为三个阶段(或步骤),分别是begin,process和e ...

  4. ZeroC ICE的远程调用框架 AMI与AMD -Why?

    在Ice有两种异步使用的方式,AMI和AMD.AMI是异步方法调用,AMD是异步方法调度(分派).前者用在代理端,后者用在饲服实现端. AMI其实就是在代理端,使用Future机制进行异步调用,而不阻 ...

  5. ZeroC ICE的远程调用框架 class与interface

    我们在ice文件中定义的class或interface,slice都会为我们生成stub存根类和skeleton骨架类.在这里要注意slice并没有分别生成两份单独用在客户端或服务端的接口给开发分发. ...

  6. ZeroC ICE的远程调用框架 ServantLocator与Locator

    ServantLocator定位的目标是Servant,而Locator定位的目标是“Ice Object”,即一个可定位的“Ice Object”代理.Servant是::Ice::Object的继 ...

  7. ZeroC ICE的远程调用框架 ThreadPool

    ThreadPool提供Reactor/Proactor服务,并且强偶合了Reactor(反应器)/Proactor(前摄器).不同于Reactor/Proactor使用线程池 进行事件处理的设计.如 ...

  8. ZeroC ICE的远程调用框架 代理引用地址

    在官方文档中称为Binding,协议-地址对的绑定.在Proxy模式中,一般地有三个参与者,Proxy,Subject以及RealSubject.Subject定义了Proxy(代理)和RealSub ...

  9. ZeroC ICE的远程调用框架 ASM与defaultServant,ServantLocator

    ASM与defaultServant,ServantLocator都是与调用调度(Dispatch)相关的. ASM是ServantManager中的一张二维表_servantMapMap,默认Ser ...

随机推荐

  1. javascript学习总结之Object.assign()方法详解

    最近再写ES6的文章时候发现自己对Object.assign()方法不太了解,之前也没有接触过所以就就查阅了相关的资料,为了自己以后肯能会用到以及对知识进行巩固,所以在这里记录下自己学习的点点滴滴,毕 ...

  2. 百万年薪python之路 -- MySQL数据库之 完整性约束

    MySQL完整性约束 一. 介绍 为了防止不符合规范的数据进入数据库,在用户对数据进行插入.修改.删除等操作时,DBMS自动按照一定的约束条件对数据进行监测,使不符合规范的数据不能进入数据库,以确保数 ...

  3. day2编程语言发展史

    1.编程语言的发展史: 机器语言 优点:执行速度够快 缺点:开发效率非常低 汇编语言(通过英文字符组成) 优点:执行效率相较于机器语言略低. 缺点:执行效率相较于机器语言略高. 高级语言 c ,c++ ...

  4. video3

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. mysql笔记一

    普通操作, 查看数据库的大小,SELECT sum(DATA_LENGTH)+sum(INDEX_LENGTH) FROM information_schema.TABLES where TABLE_ ...

  6. oracle 特殊符号替换删除处理

    1 获取ascii码 select ascii('特殊字符') from dual 2 替换 update table set testfield= replace(testfield,chr(asc ...

  7. jsp一句话木马

    <%@page import="java.io.*,java.util.*,java.net.*,java.sql.*,java.text.*"%> <%!Str ...

  8. golang 包依赖管理 godep 使用

    介绍: godep是解决包依赖的管理工具,目前最主流的一种,原理是扫描记录版本控制的信息,并在go命令前加壳来做到依赖管理. 1.安装: go get github.com/tools/godep 2 ...

  9. [2018-01-12] laravel--ORM

    建立模型 <?php namespace App; use Illuminate\Database\Eloquent\Model; class Student extends Model { / ...

  10. [考试反思]1003csp-s模拟测试58:沉淀

    稳住阵脚. 还可以. 至少想拿到的分都拿到了,最后一题的确因为不会按秩合并和线段树分治而想不出来. 对拍了,暴力都拍了.挺稳的. 但是其实也有波折,险些被卡内存. 如果内存使用不连续或申请的内存全部使 ...