将COM Events进行到底(一)

2008-04-09 04:06:47来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

通常,我们在组件和客户程序之间实现事件通知与订阅时,会采用这两种方法:回调(Callback),和连接点(ConnectionPoint)。他们的本质其实都是,订阅者将接口传递给发布者,当有事情发生时,发布者调用接口的方法。这种类型的事件叫Tightly Coupled Event(TCE),属于Request-Reply方式。
TCE的限制在于:
ü 订阅者必须知道它所请求的通知来自于哪一个发布者。发布者和订阅者紧紧绑定在一起,双方程序代码依赖于接口的定义,我们必须在编译时刻知道对方的信息(CLSID,或ProgID);
ü 要求订阅者和发布者必须同时在线。也就是说,在生存周期上必须重叠(overlap);
ü 不包含过滤或截取机制。

COM 提供了一种全新的服务:COM Events或者Loosely Coupled Events(LCE)。不过此事件非彼事件。用微软的话说就是“COM 事件不与传统 ConnectionPoints 事件关联,并且在完全不同的方案中使用。”
它的思路是,发布者亲自维护一个外部数据库(我们管它叫EventList),其中存储了订阅的所有事件的列表。发布者通过这个表知道该如何发送事件通知。订阅者也可以读入此列表,并选择它感兴趣的事件。发布者再维护另一个数据库(我们管它叫SubscribtionList),其中存储了订阅者的CLSID。从概念上讲,这个数据库相当于一个邮件列表。订阅者可以向这个库中添加自己的CLSID。发布者想要激发事件时,会检查这个数据库,找到所有订阅这个事件的订阅者的CLSID,创建每一个相关类的新对象,并调用对象的方法。
这个属于Publisher-Subscriber方式。
(图1可参看http://www.microsoft.com/CHINA/msdn/library/techart/com agvb4.gif)
Fig 1
具体执行的顺序,图2说得非常明白:
(图2可参看http://www.idevresource.com/images/articles/com eventsintro1.gif)
Fig 2 shows a typical COM events life cycle.

LCE的优点就在于:
ü 订阅者不必知道上层事件处理的细节;
ü 发布者不在运行时,订阅者也可以发出订阅请求;发布者不用理会订阅者是否在家,就可以发布通知;
ü 过滤或者截取。订阅者可以选择订阅事件中哪些他更感兴趣,比如,一个订户订阅了出版社的新书通知,但是他还可以告诉出版社只有当国外作家的新书到达时才给他通知,或者只有当价格低于50元的新书到达时候才通知他。
更多细节
发布者的事件方法执行情况:
当一个事件的方法最终返回时,
非QC的订阅者中:
临时订阅者的情况:订阅者对象已经被调用,而且方法已经返回!
永久订阅者的情况:订阅者对象已经被创建、调用、返回,而且已经被释放!

QC订阅者的情况:
所有对QC订阅者的调用已经被记录下来;
对于永久订阅者,这些记录已经被送到队列准备传送出去。

所以非QC订阅者的执行情况会影响到发布者,而QC不会。比如非QC的订阅者中如果在接收到事件通知的方法中Sleep个一分钟,那发布者的事件方法就必须老老实实等1分钟,然后再调用下一个订阅者对象。
订阅者的疑问一:
提问:
如果我的订阅者程序已经在处理一个事件了,这时候又来了一个事件通知,那么这第二个事件会被谁接收呢?
是新创建一个订阅者对象呢?还是等着当前这个事件处理完?
回答:
我认为是后者。
发布者的疑问一:
提问:
发布者可不可以位于不同的机器?
回答:
发布者分布到远程服务器上,但是事件通知仍然在中心服务器上。这种情况可以通过下面两种方法做到:
u 将EventClass所在的COM 应用导出为应用程序代理。在远程服务器上安装这个代理。
u 在远程服务器上调用该EventClass发布事件时,调用代码改为:CreateObject(“%YourEventClassProgID%”, “\\%YourCenterServerName%”)。
这样,在远程服务器上的事件发布行为,都会被转到中心服务器上的EventClass应用。
订阅者的疑问二:
提问:
订阅者是否可以位于不同的机器呢?
回答:
下面的文字是引用MSDN的《COM Events Architecture》:
Note This version of COM Events does not support a distributed event store. A subscriber must subscribe to an event on each computer from which it wants to receive notification. As an alternative, you can register the EventClass and subscriptions on a central computer and instantiate this EventClass from the remote computers on which you will publish events. Delivery of events is provided either by DCOM or queued components. For more information on using queued components, see Composing Events with Queued Components.
曾经有人做过下面的步骤试图远程订阅:
ü 远程订阅者创建一个“COMAdmin.COMAdminCatalog”的实例;
ü 远程订阅者调用COMAdmin.COMAdminCatalog的Connect方法连结至中心服务器;
ü 远程订阅者通过向中心服务器的临时订阅数据库中添加一条记录来订阅;
但是,结果是中心服务器的其他本地订阅者都接收到了事件通知,而远程订阅者却没有。
建议如果真的想远程订阅的话,可以自己实现DCOM,或者用QC。
EventClass组件的调试:
如果在VC IDE或者VB IDE中设断点调试EventClass组件,那么当事件发布时,订阅者将接收不到事件通知。
这是由于在COM 应用中EventClass组件的注册地址已经被更改为:
D:\Program Files\Microsoft Visual Studio\VB98\VB6DEBUG.DLL了!
虽然,EventCalss组件的CLSID没有变,但是不是和订阅数据库中记录的不一样了呢,所以没有通知订阅者。

制作实录:
第一步,先做一个EventClass组件:
新建一个VB DLL,Project Name为TomoTrace,Class Module Name为Trace。
代码极其简单,为:
Public Function Publish(ByVal strAuthor As String, _
ByVal strTraceType As String, _
ByVal strEventCategory As String, _
ByVal nEventID As Integer, _

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:提高团队士气

下一篇:目前开发方式的主要缺点