3.4 事件监听
事件监听在OSGi中是一种很常见的设计模式,在Bundle生命周期的不同状态相互转换时,OSGi框架会发布出各种不同的事件供事先注册好的事件监听器处理,这些事件被称为“生命周期层事件”。OSGi框架支持的生命周期层事件包括继承于BundleEvent类的,用于报告Bundle的生命周期改变的Bundle事件,以及继承于FrameworkEvent类的,用于报告框架的启动、启动级别的改变、包的更新或捕获错误的框架事件。
3.4.1 事件类型
BundleEvent和FrameworkEvent中都定义了一个返回值为int的getType()方法,这个方法用于说明该事件对象代表了什么事件类型,每一类事件用一个整数来表示。为了以后能够对事件类型进行扩充,事件监听器应当忽略不可识别的事件。Bundle事件所包含的事件类型和描述如表3-1中所示。
框架事件包含的事件类型和描述如表3-2中所示。
与Bundle状态值类似,代表事件类型的整型值也使用位掩码来描述,这便于一个事件监听器同时处理多种事件类型,示例如下:
if((event.getType() & (INSTALLED | STARTED | STOPPED)) != 0){
// 只能在INSTALLED、STARTED、STOPPED事件下执行的动作
}
3.4.2 事件分派
与BundleEvent和FrameworkEvent类相对应,OSGi规范定义了BundleListener和FrameworkListener接口来描述Bundle事件和框架事件的监听器。这两个监听器接口中分别包含了BundleListener.bundleChanged()和FrameworkListener.frameworkEvent()方法,接收到事件广播之后在这两个方法中进行相关处理,这些方法的处理动作都是默认异步执行的,不会阻塞Bundle和框架的状态转换过程。
另外,OSGi规范明确规定了必须以事件发生那一刻的监听器快照作为事件分派目标,因此可能出现在事件监听器执行时,这个监听器实际上已经不再监听当前所发生的事件的情况。具体情况笔者通过以下三个场景进行说明。
1)情景一:事件顺序如图3-4所示。
在这个场景中,监听器1不能接收到事件A,因为OSGi框架以事件发生那一刻的监听器快照作为事件分派目标,而监听器1不是在事件发生前注册的。
2)情景二:事件顺序如图3-5所示。
在这个场景中,已被注销的监听器2依然可以接收到事件B,同样是因为OSGi框架以事件发生那一刻的监听器快照作为事件分派目标。
3)情景三:事件顺序如图3-6所示。
在这个场景中,监听器3也无法接收到事件C,因为它的上下文对象(BundleContext)此时已经不存在(准确地说是存在但不可用)了。
BundleListener接口还派生了一个SynchronousBundleListener子接口,顾名思义,这个子接口被用来进行同步处理。因为STARTING和STOPPING这两个Bundle事件描述的是一个持续过程而非瞬间的状态转换,所以它们的监听器应当同步执行才是合理的,对于这两个事件,OSGi框架也只会分派给同步的监听器。
OSGi分别通过BundleContext.addBundleListener()和BundleContext.addFrameworkListener()添加Bundle事件和框架事件的监听器到OSGi框架的事件监听列表之中,添加监听器的动作一般在Bundle的Activator类中实现。