欢迎进入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 来实现更细粒度的事件过滤。

在2014-07-04 19:15上被李小翔创建

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