前面讲过,OSGi 规范定义了很多可用的 bundle,您尽管使用它们完成您的工作,而不必另外再发明轮子,OSGi 框架定义的事件管理服务,类似于 JMS,但是使用上比 JMS 简单。
OSGi 整个框架都离不开这个服务 ,因为框架里面全都依靠事件机制进行通信,例如 bundle 的启动、停止,框架的启动、停止,服务的注册、注销等等等等都是会发布事件给监听者,同时也在监听其它模块发来的自己关心的事件。 OSGi 框架的事件机制主要核心思想是:
说明:框架提供的事件服务、事件提供者、事件监听者之间的关系如下:
事件提供者 Publisher 可以获取 EventAdmin 服务,通过 sendEvent 同步(postEvent 异步)方式提交事件,EventAdmin 服务负责分发给相关的监听者 EventHandler,调用它们的 handleEvent
方法。
这里要介绍一个新的概念 Topics,其实在 JMS 里面也有用,也就是说一个事件一般都有一个主题,这样我们的事件接收者才能按照一定的主题进行过滤处理,例如只处理自己关心的主题的事件,一般情况下主题是用类似于 Java Package 的命名方式命名的。
同步提交(sendEvent)和异步提交(postEvent) 事件的区别是,同步事件提交后,等框架分发事件给所有事件接收者之后才返回给事件提交者,而异步事件则一经提交就返回了,分发在另外的线程进行处理。
1.自定义一个事件:
import java.util.Dictionary; import org.osgi.service.event.Event; public class MyEvent extends Event { public static final String MY_TOPIC = "osgi/test/helloworld/MyEvent"; public MyEvent(String arg0, Dictionary arg1) { super(MY_TOPIC, arg1); } public MyEvent() { super(MY_TOPIC, null); } public String toString() { return "MyEvent"; } }
2.注册事件服务:
import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.event.EventAdmin; @Override public String getHello() { //post a event ServiceReference ref = context.getServiceReference(EventAdmin.class.getName()); if(ref!=null) { eventAdmin = (EventAdmin)context.getService(ref); if(eventAdmin!=null) { System.out.println("post event started"); eventAdmin.postEvent(new MyEvent()); System.out.println("post event returned"); } } return "Hello osgi,service"; }
3.实现一个事件监听:
import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; public class MyEventHandler implements EventHandler { @Override public void handleEvent(Event event) { System.out.println("handle event started--"+event); try { Thread.currentThread().sleep(5*1000); } catch (InterruptedException e) { } System.out.println("handle event ok--"+event); } }
4.注册监听器:
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.Hashtable; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import osgi.test.helloworld.event.MyEvent; import osgi.test.helloworld.service.IAppService; import osgi.test.helloworld.service.IHello; public void start(BundleContext context) throws Exception { System.out.println("hello world2"); /** * 添加事件处理器 . */ String[] topics = new String[] {MyEvent.MY_TOPIC}; Hashtable<String,String[]> ht = new Hashtable<String,String[]>(); ht.put(EventConstants.EVENT_TOPIC, topics); EventHandler myHandler = new MyEventHandler(); context.registerService( EventHandler.class.getName(), myHandler, ht); System.out.println("event handler registered"); /** * Test hello service from bundle1. */ IHello hello1 = (IHello) context.getService( context.getServiceReference(IHello.class.getName())); System.out.println(hello1.getHello()); }
备注:上述服务的注册和获取跟上一章类似,不同的是eclipse提供的事件服务的实现相对来说复杂点。另外,EventConstants.EVENT_TOPIC用来描述事件的主题,一个事件一般都有一个主题,这样我们的事件接收者才能按照一定的主题进行过滤处理,例如只处理自己关心的主题的事件,一般情况下主题是用类似于 Java Package 的命名方式命名的。