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. UI测试之元素定位

    定位方式优先级选择:  ID>Name>CSS>XPath 1.使用id定位 2.使用name定位 3.使用class定位 4.使用css选择器定位 示例xml: <?xml ...

  2. sublime设置 reindent 快捷键

    设置快捷键 使用快捷键 cmd + shift + p 打开控制面板 输入 key 关键词 点击进入 Key Bindings -User 添加如下代码 { "keys": [&q ...

  3. Java基础(二十四)Java IO(1)输入/输出流

    在Java API中,可以从其中读入一个字节序列的对象称作输入流,而可以向其中写入一个字节序列的对象称为输出流. 输入流的指向称为源,程序从指向源的输入流中读取数据. 输出流的指向是字节要去的目的地, ...

  4. Android 正则表达式,Pattern,Matcher基本使用

    Pattern类:      Pattern的创建:      Pattern pattern =Pattern.complie(String regex)     参数说明:regex:是一个正则表 ...

  5. unityevent与持续按键触发

    上一篇中提到一种鼠标按下时的事件触发,即采用eventtrigger设定pointerdown和pointerup并绑定相应事件.但是若要实现持续按键则需要对绑定的每个方法都添加实现持续按键方法.所以 ...

  6. js奥义:原型与原型链(2)

    回顾:上一篇讲了原型对象与prototype和__proto__(传送门 )三者之间的关系 三:constructor constructor [kənˈstrʌktə(r)] :构造器,  这是子类 ...

  7. JAVA基础知识注意事项

    JAVA核心技术卷一 (第十版) 下面是需要注意的: 只有方法名和参数类型叫做方法的签名, 不同的返回类型值不能作为方法的签名.(4.6.1) 这是域与局部变量的主要不同点. 必须明确地初始化方法中的 ...

  8. c++数据结构随笔(1)

    创建数据结构单链表的时候,突然碰到基础不牢固的问题,指针问题.就当复习指针了. 问题是如果三个指针a和b和r, b=a; b->next = r; 那么a->next会不会变? 然后写了一 ...

  9. 转:linux环境mysql root用户密码重置

    经常设置了mysql的root密码,就忘记掉了,这种事还是经常发生的.转自他人(http://www.osyunwei.com/archives/2014.html),权做笔记.linux环境下,解决 ...

  10. 解决本地无法访问vm虚拟机上centos7服务器中已配置好的hugo站点的问题

    一.配置VM网络连接 打开vm,找到"编辑",打开"虚拟网络编辑器" 选中下面截图中的上方为类型为"NAT模式"那一栏,然后点击下方的&qu ...