OSGI入门和整合Spring


OSGI 入门和整合 Spring 概述 本文用于 OSGI 基本入门,并添加对 Spring 的整合,本文假设读者对 Eclipse、OSGI, Spring 的概念和用法有基本了解,本文仅供参考,希望起到抛砖引玉的效果,希望对大家能 有帮助,能节省一点查资料的时间就善莫大焉了。 若发现纰漏和疑问,望不吝指教——E-Mail:Caichaowei@gmail.com。 感谢 Powerpiggy,Hypaspist 的指导和帮助。 蔡超伟 2008 年 4 月 一、创建提供服务的 OSGI Bundle 1. 创建一个 Plug-in 工程 2. 填入工程名,如图选择 3. 直接下一步,然后点击 Finish,会显示如下图: 4. 选择 Dependencies,添加 5. 点击 debug 的虫子图标,选择 Open Debug Dialog… 出现下图界面后,保证在 Workspace 中选择刚创建的 bundle,在点击“Add Required Bundles”, 确保如下 3 个被选中: org.eclipse.osgi org.eclipse.osgi.services org.eclipse.equinox.ds 注意最后一个 org.eclipse.equinox.ds 需要手工指定,该包如果你的 Eclipse 下没有则需要下载 安装,只有具有该 jar 包才能从以配置文件的方式注册服务(见后述的 service.xml 文件)。 6. 点击 Debug 后在控制台显示 至此,一个最基本的 Bundle 就完成了,但此时它还不能对外提供任何服务。 7. 创建一个接口 IDisplay,并且创建一个实现类 Display,实现其显示信息的方法 setDescInfor,内容就是将传入的参数在控制台打印出来,项目结构如图: 文件内容如下: /** * IDisplay.java */ public class Display implements com.infotech.bpr.autodisplay.display.IDisplay { public void setDescInfor(String strInfor) { System.out.println(strInfor); } } /** * Display.java */ package com.infotech.bpr.autodisplay.display; import org.osgi.service.component.ComponentContext; public class Display implements com.infotech.bpr.autodisplay.display.IDisplay { public void setDescInfor(String strInfor) { System.out.println("显示:" +strInfor); } /* activate 方法会在 Bundle 加载完毕后自动调用,deactivate 会在 Bundle 卸载 时自动调用。*/ protected void activate(ComponentContext context) { System.out.println("显示器激活"); } protected void deactivate(ComponentContext context) { System.out.println("显示器卸载"); } } /** * Activator.java */ package com.infotech.bpr.autodisplay; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { public void start(BundleContext context) throws Exception { System.out.println("显示组件启动"); } public void stop(BundleContext context) throws Exception { System.out.println("显示组件停止"); } } 创建一个叫 OSGI-INF 的目录,下面创建一个名为 service.xml 的文件 内容如下: 上述内容的含义为声明一个名为 DisplayService 的组件,它对外提供接口 Idisplay,实现类 是 Display。 8. 在 MANIFEST.MF 文件编辑器里,选择 Runtime,在 Exported packages 里添加 Idispaly 接口所在的包 在源码里添加如下一行:Service-Component: OSGI-INF/service.xml 上述操作的意思为:此 Bundle 对外提供的服务包为 com.infotech.bpr.autodisplay.display,其说明文件为 OSGI-INF/service.xml 9. 最后 MANIFEST.MF 的内容如下: Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Autodisplay Plug-in Bundle-SymbolicName: com.infotech.bpr.autodisplay Bundle-Version: 1.0.0 Bundle-Activator: com.infotech.bpr.autodisplay.Activator Bundle-Vendor: INFOTECH Import-Package: org.osgi.framework;version="1.4.0", org.osgi.service.component;version="1.0.0" Export-Package: com.infotech.bpr.autodisplay.display Service-Component: OSGI-INF/service.xml 简单说明: Import-Package:指需要依赖的包 Export-Package:指对外暴露的接口包名 Service-Component:指定提供服务的组件说明文件信息 这样一个提供简单打印信息服务的 Bundle 就完成了! 二、创建使用服务的 OSGI Bundle 1. 按第一部分所述 1~6 步创建一个新的 Bundle 工程 2. 在 dependencies 的 Imported Packages 里面添加第一部分所创建的提供服务的 bundle 包 3. 生成准备调用服务的类 AutoTallyTaskPro,其中定义一个类型第一部分中定义的接口 IDispay 的变量 display,生成 getter,setter,另外写一个 unSetDisplay 方法,用于释放 display 对象。 最后文件内容如下: /** * Activator.java */ package com.infotech.brp.autotally; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { public void start(BundleContext context) throws Exception { System.out.println("自动记账程序启动"); } public void stop(BundleContext context) throws Exception { System.out.println("自动记账程序停止"); } } /** * AutoTallyTaskProc.java */ package com.infotech.brp.autotally; import java.util.Map; import com.infotech.bpr.autodisplay.display.IDisplay; import org.osgi.service.component.ComponentContext; public class AutoTallyTaskProc implements IAutoTallyTaskProc { private IDisplay display; public IDisplay getDisplay() { return display; } public void setDisplay(IDisplay dispaly) { System.out.println("自动记账 setDisplay"); this.display = dispaly; } public void unSetDisplay(IDisplay dispaly) { System.out.println("自动记账 unSetDisplay"); if (this.display == dispaly) { display = null; } } protected void activate(ComponentContext context) { display.setDescInfor("自动记账激活,调用显示器"); } public void deactivate(ComponentContext context) { display.setDescInfor("自动记账停止调用显示器"); } } 4. 下面配置注入 IDisplay 接口对象:创建一个叫 OSGI-INF 的目录,下面创建一个名为 components.xml 的文件,内容如下: 在上面声明了这个组件的名称为 Autotally , 实现类为 com.infotech.brp.autotally.AutoTallyTaskProc,还指定了其中绑定服务的类型 和绑定、解绑方法。 5. 在 MANIFEST.MF 中添加:Service-Component: OSGI-INF/components.xml , 最后 MANIFEST.MF 的内容如下: Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Autotally Plug-in Bundle-SymbolicName: com.infotech.brp.autotally Bundle-Version: 1.0.0 Bundle-Activator: com.infotech.brp.autotally.Activator Bundle-Vendor: INFOTECH Import-Package: com.infotech.bpr.autodisplay.display, org.osgi.framework;version="1.4.0", org.osgi.service.component;version="1.0.0" Service-Component: OSGI-INF/components.xml 6. 运行后能看到组件的调用过程: 输入 ss 查看组件运行情况如下图: 输入 stop 86,然后输入 stop 87,如下图: 至此,一个完整的简单 OSGI 服务创建和调用实例已经全部展示完毕,在往下的过程中 我们将整合 Spring 和 OSGI 框架。 三、 对服务使用 Spring 1. 接下来将服务 Bundle 放入 Spring 环境中处理,首先下载 Spring Dynamic Modules for OSGi(tm) Service Platforms 并安装,如图: 在 Open debug dialog 的 bundle 中添加上面的包(第一、二部分所添加的包全部保留)。 2. 在项目下添加 SPRING-INF 目录,下面添加一个名为 springservice.xml 的文件,如图 内容如下: 3. 将 MANIFEST.MF 的内容改成 Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Autodisplay Plug-in Bundle-SymbolicName: com.infotech.bpr.autodisplay Bundle-Version: 1.0.0 Bundle-Activator: com.infotech.bpr.autodisplay.Activator Bundle-Vendor: INFOTECH Import-Package: org.osgi.framework;version="1.4.0", org.osgi.service.component;version="1.0.0" Export-Package: com.infotech.bpr.autodisplay.display Spring-Context: SPRING-INF/springservice.xml 注意和第一部分的 MANIFEST.MF 内容对比,会发现 Service-Component 被替换成了 Spring-Context. 4. 这时再运行,控制台打印信息如图: 黑字部分显示出 Bundle 已经正常运行,红字为 Spring 打印出的调试信息。 注意:与第一、二部分的运行相比,少了输出:“显示器激活”,即 Display 类的 Activate 方 法没有执行(随后说明)。 输入 ss 查看 Bundles 运行状态后再停止之,如下图: 对比第一、二部分的运行效果,可以发现在 unSet 之后,没有“显示器卸载”的输出,即其 deactivate 方法也没有执行(随后说明)。 关于 activate 和 deactivate 不会自动执行,笔者没有找到好的解决方法。但根据 Spring-DM 的规范,它并不推荐如此,因为两个方法的声明用到 ComponentContext ,换句话讲,这 将使你的代码和执行环境上下文绑定,除非逼不得已,并不支持这样做。笔者现在采用的方 法是将服务调用者本身也定制为一个服务(但不需对外提供任何接口,仅仅是注册一个服 务),这样即可利用其 registered 和 unregistered 事件来实现 activate 和 deactivate 一样的功能。 四、 对服务调用者使用 Spring 1 同第三部分的 1、2 步骤,只是 xml 文件内容为: 简单说明如下: bean 元素声明了一个 id 为 AutoTallyTaskProc 的 bean osgi:reference 元素声明了导入提供 Idisplay 接口的服务,使用 AutoTallyTaskProc 作为其监听 器,在绑定和解绑服务时分别调用 onBind 和 onUnbind 方法。 osgi:service 元素声明了服务 SautoTally,提供接口为 IautoTallyTaskProc(空接口),实现 Bean 为 AutoTallyTaskProc 。注册注销监听器也是 AutoTallyTaskProc ,注册完毕执行: serviceRegistered,注销完毕执行:serviceUnregistered。 2 改造 AutoTallyTaskProc 的代码如下: package com.infotech.brp.autotally; import java.util.Map; import com.infotech.bpr.autodisplay.display.IDisplay; public class AutoTallyTaskProc implements IAutoTallyTaskProc{ private IDisplay display; public IDisplay getDisplay() { return display; } public void setDisplay(IDisplay dispaly) { System.out.println("自动记账 setDisplay"); this.display = dispaly; } public void serviceRegistered(IAutoTallyTaskProc serviceInstance, Map serviceProperties) { System.out.println("自动记账服务注册完毕"); display.setDescInfor("Hello"); } public void serviceUnregistered(IAutoTallyTaskProc serviceInstance, Map serviceProperties) { System.out.println("自动记账服务注销完毕"); } public void onBind(IDisplay display, Map argMap) throws Exception { System.out.println("绑定"+ display.getClass().getName()); this.display = (IDisplay)display; } public void onUnBind(IDisplay display, Map argMap) throws Exception { System.out.println("解绑"+ display.getClass().getName()); if (this.display == display) { display = null; } }} 另外再写一个空的接口 IautoTallyTaskProc,代码略。 注意:上面所述的定义方式和代码结构是笔者所推荐的,从代码可以看出,没有任何 Spring 和 OSGi 的 API 引用。 3 最后的代码结构如下: 4 执行时应按顺序打印启动、绑定服务,调用服务的信息。OK! 五、 其他 获取服务有多种方式,若使用如下 XML 文件配置方式需要 org.eclipse.equinox.ds_1.0.0.v20070226.jar 的支持。 在 OSGI-INF/server.xml 中说明: 获取服务的第二种方法,在 start 里: /*import org.osgi.framework.ServiceReference; simpleLogServiceTracker = new ServiceTracker(context, 接口类.class.getName(), null); simpleLogServiceTracker.open(); simpleLogService = (接口类) simpleLogServiceTracker.getService(); if(simpleLogService != null) simpleLogService.setLogInfo("OSGI框架已经成功启动了,一切运行正 常"); else System.out.println("没有获得服务"); */ 获取服务第三种方法: //ServiceReference serviceRef = context.getServiceReference(接 口类.class.getName()); //Logger logger = (接口类) context.getService(serviceRef); //logger.setLogInfo("OSGI 框架已经成功启动了,一切运行正常"); 若使用后两种方法,需要在 Stop 方法里卸载 : // ServiceReference serviceRef = context.getServiceReference(接口 类.class.getName()); /* if(simpleLogService != null) simpleLogService.setLogInfo("正在结束使用"); simpleLogServiceTracker.close(); simpleLogServiceTracker = null; simpleLogService = null; */
还剩20页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

zhulongpz

贡献于2010-12-01

下载需要 20 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf