OSGi的服务层(Service Layer)为bundle之间的解耦合及服务引用提供的强大而又灵活的实现机制。通过BundleActivator控制组件的生命周期,通过BundleContext 与其他组件和服务交互。但是,OSGi服务层在提供强大的功能的同时,也给使用者造成了很大的困惑,比如,组件的启动顺序,服务的查找策略等等。OSGi通过Declarative Service给出了一种通过XML配置文件发布和绑定服务的功能,用户只需要定义XML文件即可向OSGi环境中发布服务对象和获取其他bundle组件发布的服务。
在OSGi编程过程中,获取其他Bundle提供的服务是比较复杂的,尤其是获取多个服务时需要做很多重复性的工作。有没有更为简单的方式实现服务的发布和绑定呢?最近在Equinox邮件列表中看到Patrick的向equinox开发组的一项提议,建议将Service Activator Toolkit(SAT)组件添加到Equinox项目中,SAT目前位于Eclipse 技术项目OHF中。
SAT大大简化了OSGi Service Bundle开发的复杂性。用户可以通过SAT插件引用服务,发布服务,自定义Bundle Activator。下面是SAT插件的功能略图:
上图展示了如何引用和发布服务
上图展示了如何定制BundleActivator。
下面通过几行简单的代码展示SAT如何简化服务的发布和引用。
//服务的发布
public class Activator extends BaseBundleActivator { protected void activate() { LogUtility.logInfo("The Hotdog Vendor bundle has been activated"); //$NON-NLS-1$ addExportedVendorService(); }
//将HotdogVendor服务发布到OSGi环境中
private void addExportedVendorService() { VendorService service = new HotdogVendor(); Dictionary properties = new Hashtable(11); properties.put(VendorService.SPICINESS_PROPERTY, new Integer(10)); addExportedService(VendorService.SERVICE_NAME, service, properties); }
protected void deactivate() { LogUtility.logInfo("The Hotdog Vendor bundle has been deactivated"); //$NON-NLS-1$ }}
//服务的引用
public class Activator extends BaseBundleActivator { private Customer customer;
//组件启动激活
protected void activate() { LogUtility.logInfo("The Customer bundle has been activated"); //$NON-NLS-1$ VendorService vendor = getVendorService(); Customer customer = getCustomer(); customer.setVendor(vendor); customer.eat(); }
//组件停止注销
protected void deactivate() { Customer customer = getCustomer(); customer.setVendor(null); LogUtility.logInfo("The Customer bundle has been deactivated"); //$NON-NLS-1$ }
private Customer getCustomer() { return customer; }
//声明需要引用的服务的名称
protected String[] getImportedServiceNames() { return new String[] { VendorService.SERVICE_NAME }; }
//设定服务过滤条件
private String getVendorFilter() { StringBuffer buffer = new StringBuffer(50); buffer.append('('); buffer.append(VendorService.SPICINESS_PROPERTY); buffer.append("<="); //$NON-NLS-1$ buffer.append(8); buffer.append(')'); String filter = buffer.toString(); return filter; }
//获取HotdogVender服务
private VendorService getVendorService() { return (VendorService) getImportedService(VendorService.SERVICE_NAME); }
private void setCustomer(Customer customer) { this.customer = customer; }
protected void start() throws Exception { LogUtility.logInfo("The Customer bundle has been started"); //$NON-NLS-1$ Customer customer = new Customer(); setCustomer(customer); String filter = getVendorFilter(); addImportedServiceFilter(VendorService.SERVICE_NAME, filter); }
protected void stop() throws Exception { setCustomer(null); LogUtility.logInfo("The Customer bundle has been stopped"); //$NON-NLS-1$ }}
SAT目前从Eclipse CVS上可以获取到。CVS的访问地址为:
:pserver:dev.eclipse.org:/cvsroot/technology org.eclipse.ohf/plugins/org.eclipse.soda.sat