一般动作
登录
Wiki: BROPEN ▼: Document Index
»
Space: FAQ ▼: Document Index
»
Page: grails-platform-core插件的事件总线（Events Bus）
搜索
zh
页面动作
导出 ▼: 以PDF格式导出 以RTF格式导出 以HTML格式导出
更多动作 ▼: 打印预览 察看源码
欢迎进入Wiki » FAQ » grails-platform-core插件的事件总线（Events Bus）?

# grails-platform-core插件的事件总线（Events Bus）?

在2014-07-04 19:23上被李小翔修改
评论 (0) · 附件 (0) · 记录 · 信息

BroToolkit 中集成了插件 platform-core，BroFramework、BroBPM中都使用其事件总线（插件的其他功能都被禁用了）作为默认的事件总线（如流程提醒服务）；此外，还通过 CometD 插件实现了类似的异步消息总线、尤其是浏览器和服务器之间的消息。

这里简单介绍一下常用API的基本使用，更多信息参考 Events Bus（英文）。

# 事件触发（Sending Events）

在 Domain、Controller、Service 类中，可以直接调用 event 方法发起一个事件：

- event ( topic, [data, params, callbackClosure] )
- event ( Map args, [callbackClosure] )

主要参数包括：

- topic: 主题，监听器通过 topic 和 namespace 来监控频道
- data: 传递给监听器的数据
- params：一些参数，Map格式，常用的有 fork（是否异步，默认为true）、namespace/for（主题所在的命名空间，默认为 app）、onError、onReply
- args：包含上面所有的Map
- callbackClosure：事件执行完后的回调闭包

个人更喜欢第二种调用方式，示例如下：

// 异步事件（多线程）
event( for: bropen.bpm.Constants.PLUGIN_NAME, topic: "taskAsync", data: [foo:1, bar: 2], fork: true )
// 同步事件（单线程，如果监听器中有异常，则会一直抛到当前线程，并导致后面的代码不再执行）
event( for: bropen.bpm.Constants.PLUGIN_NAME, topic: "taskSync", data: [foo:1, bar: 2], fork: false )

该方法返回一个 EventReply 对象（实现了Future接口），提供了下面的一些方法：

- List<Object> getValues() : 获得所有监听器的返回值
- Object getValue() : getValues() 的第一个
- int size() : 触发的监听器数量
- List<Throwable> getErrors() : 错误列表
- boolean hasErrors() : 是否有异常
- EventReply waitFor() : 等待所有监听器执行完毕
- EventReply waitFor(long time) : 等待所有监听器执行完毕、或者一定时间

需要注意的是，上面的调用任何方法，都会导致当前线程等待，除了异常处理方式不一样外，效果和同步事件类似。

此外，可以使用通配符后缀在多个频道触发事件，如：

// 所有以"role-"开头的命名空间的、以”chat-“开头的主题
event for:'role-*', topic:'chat-*', data:session.user
// app命名空间的所有主题
event '*'

# 事件监听（Listening Events）

有几种事件监听的方式。

常用的是在 Service 类中，使用注解 @grails.events.Listener 来注册监听方法，该方法会直接编译到class文件中，因此，需要谨慎使用常量。

示例如下：

class SomeService{
@grails.events.Listener(namespace = bropen.bpm.Constants.PLUGIN_NAME, topic = 'taskAsync')
def myMethod(Map data){
do something ...
}
}

这里的监听方法一般只有一个参数，表明要监听频道的数据类型（如果相同频道会发送不同类型的数据，可以使用参数类型进行过滤，或者使用 Object 类型监听所有）；此外，还可以使用 EventMessage 类型的参数来监听所有。

同样，这里的命名空间、主题参数也支持通配符后缀，如：

@grails.events.Listener(namespace = "role-*", topic = 'chat-*')

其次，可以在 Domain、Controller、Service 类中，调用 on 方法来动态注册一个监听器，如：

class User() {
def bootStrapInit() {
// 监听命名空间 foobar 下的 taskAsync 事件
on("foobar", "taskAsync") { Map data->
do something...
}
// 监听命名空间 app 下的 taskAsync 事件
on("taskAsync") {
do something...
}
}
}

每一个监听器会生成一个唯一ID，格式为： [namespace://]topic[:package.Class][#method][@hashcode]。可以通过这个ID来统计、删除监听器，如：

//count every listeners subscribed to 'mytopic' inside TestService
countListeners("mytopic:my.TestService")
//count every listeners using gorm namespace
countListeners("gorm://*")
//remove every listeners in TestService
removeListeners("*:my.TestService")

# 监听 GROM 事件（Listening GORM events）

在Grails中，可以通过多种方式来监听Domain实例的增删改查等事件，比如Domain类中的 afterInsert 等事件、通用的自定义事件（Custom Event Listeners）、通用的Hibernate事件（Hibernate Events），详见官方手册。

这里，还可以通过命名空间 gorm 来监听Domain实例的增删改操作，如：

class SomeService{
@Listener(namespace = 'gorm')
void afterInsert(Author author) {
println "after save author - $author.name"
}
@Listener(topic = 'beforeInsert', namespace = 'gorm')
void beforeInsertBook(Book book) {
println "will insert book - $book.title"
}
//Will catch everything since we don't filter on the subject by using EventMessage
@Listener(topic = 'before*', namespace = 'gorm')
void beforeEachGormEvent(EventMessage message) {
println "gorm event $message.event on domain $message.data.class"
}
}

此外，还可以通过 Events Artifact 来实现更细粒度的事件过滤。

标签： 事件 BroToolkit BroFramework
在2014-07-04 19:15上被李小翔创建

- 评论 （0）
- 附件 （0）
- 记录
- 信息

# 快速链接

- 首页
- 新闻动态
- FAQ

Copyright © 2013 北京博瑞开源软件有限公司
京ICP备12048974号