本文讲到的例子是仿照网上甚为流行的一个例子,但苦于一直未找到源码,网上贴的都是一些转帖,代码片段,估计初学者很难将其还原并调通!我最开始弄这个咚咚的时候,其过程之痛苦,难以言喻,所以想着仿照该例子的设计,给予实现,文后贴出源码,希望能帮到大家。 创建4个bundle之后的工程目录如下图所示:
package osgi.example.compute; public interface Compute { public String computeNums(int x, int y); } 2. bundle osgi.example.compute.add add bundle是对compute bundle的具体服务实现,在MANIFEST.MF文件需要引入osgi.example.compute包;当然也可以通过添加依赖bundle的形式,即不引入包,而直接在Required Plug-ins中添加compute bundle。如下图所示: 注意:OSGi官方指出,当需要用到其他bundle的类型时,不提倡依赖bundle,应该尽可能采用Import-package的方式引入包,因为依赖bundle可能在加载bundle的时候发生问题。 add bundle的工程结构如下图所示:
通过引入osgi.example.compute包,osgi.example.compute bundle被加到了add bundl的classpath当中,解决了开发时期的类型识别问题。 package osgi.example.compute.add; import osgi.example.compute.Compute; public class Add implements Compute { public String computeNums(int x, int y) { int s = x + y; String result = "The Sum is---" + String.valueOf(s); return result; } } Compute的实现已经实现了,那么如何将其发布出去呢?这个是由Spring DM负责,Spring DM利用OSGi命名空间下的<service>元素将bean导出为OSGi服务。最简单的形式为: <beans:bean id="beanToPublish" class="com.xyz.imp.MessageServiceImp"/> <service ref="beanToPublish" interface="com.xyz.MessageService"/> 从示例中可以看出,beanToPublish被service元素声明导出。 <?xml version="1.0" encoding="UTF-8"?> 如此一来,其他bundle就能通过spring dm引入接口类型为osgi.example.compute.Compute的服务了,spring dm将通过一定的服务查找策略,返回匹配的服务。<beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:osgi="http://www./schema/osgi" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans.xsd http://www./schema/osgi http://www./schema/osgi/spring-osgi.xsd"> <bean id="addOsgiService" class="osgi.example.compute.add.Add"> </bean> <osgi:service id="addService" ref="addOsgiService" interface="osgi.example.compute.Compute"> </osgi:service> </beans> 3. bundle osgi.example.compute.multiply 该bundle和add bundle相似,在这就不赘述了。 顾名思义,该bundle将作为add 、multiply两个bundle的客户bundle,演示如何导入服务。 package osgi.example.client; import osgi.example.compute.Compute; public class Client { /** * 为了方便测试,采用Spring的构造注入方式,直接在构造函数中调用Compute服务 * @param compute */ public Client(Compute compute){ System.out.println(compute.computeNums(5, 6)); } } 另外,因为client用到了其他几个bundle的类型,所以需要导入相应的包,步骤在上面已有讲到。 <reference id="beanToPublish" interface="com.xyz.MessageService"/> 如果需要用到该服务,如某个bean包含一个com.xyz.MessageService属性,则配置该bean如下所示: <bean id="referenceBean" class="com.nci.ReferenceBean"> reference元素还有一些高级属性,详情请见spring dm reference。<property name="messageService" ref="beanToPublish"/> </bean> 看一下client的spring配置文件: <?xml version="1.0" encoding="UTF-8"?> 从上面的示例,我们可以发现,服务的导出的时候都是基于接口的,服务的引用也是基于接口的,不过spring dm支持基于类的导出、导入,但是还是建议尽量基于接口,应该记住面向接口编程的思想,以应对将来有可能发生的改变。<beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:osgi="http://www./schema/osgi" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans.xsd http://www./schema/osgi http://www./schema/osgi/spring-osgi.xsd"> <bean id="OSGiClient" class="osgi.example.client.Client"> <constructor-arg ref="ComputeService"> </constructor-arg> </bean> <osgi:reference id="ComputeService" interface="osgi.example.compute.Compute" cardinality="1..1"> </osgi:reference> </beans> 5. 运行 由于add和multiply都是基于Compute接口对外导出服务,那么Client到底导入的是哪个服务呢?默认情况下,会导入启动较早的bundle服务(OSGi在bundle启动时,会为其分配一个ID值,启动越早,该值越小)。 运行之前,我们需要做这么一件事,在window->preferences->plug-in development->Target Platform面板中,将Target指定为Spring DM…,如下图所示: 之后就可以配置运行了,随便在一个bundle工程上右键,Run As->Run Configurations,新建一个OSGi Platform运行项(右键OSGi Platform即可),如下图所示: 需要勾选中spring bundle版(2.5.6),spring dm的几个核心包:core、extender、io再点validate bundles按钮,校验是否已全部选中其依赖的bundle。然后即可点击运行了。 6. 总结 通过该文档,我们已经清楚了,如何使用Spring DM导出、导入服务。Spring DM的一些高级特性请查阅spring dm reference。 |
|