`

Spring与OSGI整合 计算器例子(转) +附整合代码和spring-osgi核心jar

    博客分类:
  • OSGI
阅读更多

开发一组计算器bundle实例

 

本节讲到的例子是仿照网上甚为流行的一个例子,但苦于一直未找到源码,网上贴的都是一些转帖,代码片段,估计初学者很难将其还原并调通!我最开始弄这个咚咚的时候,其过程之痛苦,难以言喻,所以想着仿照该例子的设计,给予实现,文后贴出源码,希望能帮到大家。
该例子是一个关于计算器的实例,osgi.example.compute bundle(下文简称compute bundle)提供了统一的计算接口:Compute,另外两个bundle分别为osgi.example.compute.add(下文简称add bundle)和osgi.example.compute.multiply(下文简称multiply bundle),在这两个bundle中,各自对compute bundle进行不同的实现,一个实现加法,一个实现乘法。另外还有一个服务消费者osgi.example.compute.consumer bundle(下文简称consumer bundle),consumer bundle负责消费add bundle和multiply bundle提供的服务。上述4个bundle之间的关系如下图所示:

创建4个bundle之后的工程目录如下图所示:

通过该示例,将演示如何利用Spring DM发布和调用OSGi服务,同时还将演示OSGi的动态服务调用能力。

 

 

3.1. bundle osgi.example.compute

 

compute bundle只提供一个接口——Compute,因此无需依赖更多的bundle,只需最基本的osgi即可。因为不涉及注册资源之类的,所以也无需Activator入口类,这个例子的四个bundles都没用用到Activator接口,实现Acitivator接口的类应该是这个bundle的开启时的入口类,而这里没用用到它,这四个bundle同样可以开启成active状态。
Computer接口源代码如下所示:

  
Java代码 复制代码 收藏代码
  1. package osgi.example.compute;   
  2.   
  3. public interface Compute {   
  4.     public String computeNums(int x, int y);   
  5. }  
package osgi.example.compute;

public interface Compute {
	public String computeNums(int x, int y);
}

 

 

3.2. bundle osgi.example.compute.add

 

add bundle是对compute bundle的具体服务实现,在MANIFEST.MF文件需要引入osgi.example.compute包;当然也可以通过添加依赖bundle的形式,即不引入包,而直接在Required Plug-ins中添加compute bundle。如下图所示,可以看到有Required Plug-ins和Imported Packages两种方式,用Import Packages可能会好一点,至少轻装一点

 

 

注意:OSGi官方指出,当需要用到其他bundle的类型时,不提倡依赖bundle,应该尽可能采用Import-package的方式引入包,因为依赖bundle可能在加载bundle的时候发生问题。

 

add bundle的工程结构如下图所示:

 

 

通过引入osgi.example.compute包,osgi.example.compute  bundle被加到了add bundl的classpath当中,解决了开发时期的类型识别问题。
这样一来,在add bundle中就能使用compute bundle中的接口了,Computer接口的实现如下:

  
Java代码 复制代码 收藏代码
  1. package osgi.example.compute.add;   
  2.   
  3. import osgi.example.compute.Compute;   
  4.   
  5. public class Add implements Compute {   
  6.   
  7.     public String computeNums(int x, int y) {   
  8.         int s = x + y;   
  9.         String result = "The Sum is---" + String.valueOf(s);   
  10.         return result;   
  11.     }   
  12. }  
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服务。最简单的形式为:

  
Java代码 复制代码 收藏代码
  1. <beans:bean id="beanToPublish" class="com.xyz.imp.MessageServiceImp"/>   
  2. <service ref="beanToPublish" interface="com.xyz.MessageService"/>  
<beans:bean id="beanToPublish" class="com.xyz.imp.MessageServiceImp"/>
<service ref="beanToPublish" interface="com.xyz.MessageService"/>

 

从示例中可以看出,beanToPublish被service元素声明导出。
另外,service结点还有一些高级属性,如depends-on、context-class-loader、ranking等待,详情请看spring dm reference。
首先,需要在add bundle的工程根目录下的”META-INF”的文件夹下创建一个文件夹,取名”spring”,Spring DM能够自动解析该文件夹下所有的spring配置文件。spring配置文件的具体内容如下所示:

  
Java代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  4.     xmlns:osgi="http://www.springframework.org/schema/osgi"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans                         http://www.springframework.org/schema/beans/spring-beans.xsd   
  6.                         http://www.springframework.org/schema/osgi                          http://www.springframework.org/schema/osgi/spring-osgi.xsd">   
  7.     <bean id="addOsgiService" class="osgi.example.compute.add.Add">   
  8.     </bean>   
  9.     <osgi:service id="addService" ref="addOsgiService"  
  10.         interface="osgi.example.compute.Compute">   
  11.     </osgi:service>   
  12. </beans>  
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:osgi="http://www.springframework.org/schema/osgi"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 						http://www.springframework.org/schema/beans/spring-beans.xsd
                      	http://www.springframework.org/schema/osgi                       	http://www.springframework.org/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>

 

如此一来,其他bundle就能通过spring dm引入接口类型为osgi.example.compute.Compute的服务了,这里的osgi:service标签的id就是服务的名称,就是将bean转为服务的调用时的名称,ref为引用的是哪个bean,而interface指明只要是这个接口的定义处,都可能会用到这个服务,说可能,是因为一个接口的多个实现,也就是有多样的服务来实现,那调用时就取决于spring dm了,spring dm将通过一定的服务查找策略,返回匹配的服务。

 

3.3. bundle osgi.example.compute.multiply

 

该bundle和add bundle相似,在这就不赘述了。

 

3.4. bundle osgi.example.compute.client

 

顾名思义,该bundle将作为add 、multiply两个bundle的客户bundle,演示如何导入服务。
OSGi的测试工作比较麻烦,这方面还没研究,在这里利用spring实例化bean的时期,从构造函数入手,对服务进行测试。Client类的实现很简单,如下所示:

 
Java代码 复制代码 收藏代码
  1. package osgi.example.client;   
  2.   
  3. import osgi.example.compute.Compute;   
  4.   
  5. public class Client {   
  6.     /**  
  7.      * 为了方便测试,采用Spring的构造注入方式,直接在构造函数中调用Compute服务  
  8.      * @param compute  
  9.      */  
  10.     public Client(Compute compute){   
  11.         System.out.println(compute.computeNums(56));   
  12.     }   
  13. }  
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的类型,所以需要导入相应的包,步骤在3.2一节已有讲到。
spring dm靠<reference>元素来引入服务,最简单的形式如下所示:

  
Java代码 复制代码 收藏代码
  1. <reference id="beanToPublish" interface="com.xyz.MessageService"/>  
<reference id="beanToPublish" interface="com.xyz.MessageService"/>

 

如果需要用到该服务,如某个bean包含一个com.xyz.MessageService属性,则配置该bean如下所示:

Java代码 复制代码 收藏代码
  1. <bean id="referenceBean" class="com.nci.ReferenceBean">   
  2.     <property name="messageService" ref="beanToPublish"/>   
  3. </bean>  
<bean id="referenceBean" class="com.nci.ReferenceBean">
	<property name="messageService" ref="beanToPublish"/>
</bean>

 

reference元素还有一些高级属性,详情请见spring dm reference。
看一下client的spring配置文件,这里用osgi:reference标签来引用服务,上面的配置中用osgi:service标签来发布服务

  
Java代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd   
  5.                       http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">   
  6.   
  7.     <bean id="OSGiClient" class="osgi.example.client.Client">   
  8.         <constructor-arg ref="ComputeService">   
  9.         </constructor-arg>   
  10.                 </bean>   
  11.                 <osgi:reference id="ComputeService" interface="osgi.example.compute.Compute" cardinality="1..1">   
  12.                 </osgi:reference>   
  13. </beans>   
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                      http://www.springframework.org/schema/osgi http://www.springframework.org/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> 

 

从上面的示例,我们可以发现,服务的导出的时候都是基于接口的,服务的引用也是基于接口的,不过spring dm支持基于类的导出、导入,但是还是建议尽量基于接口,应该记住面向接口编程的思想,以应对将来有可能发生的改变。

 

 

3.5. 运行

 

由于add和multiply都是基于Compute接口对外导出服务,那么Client到底导入的是哪个服务呢?默认情况下,会导入启动较早的bundle服务(OSGi在bundle启动时,会为其分配一个ID值,启动越早,该值越小)。
运行之前,我们需要做这么一件事,搭建Spring-DM的运行环境:

(1)先到http://www.springsource.org/osgi上去下载Spring DM:spring-osgi-1.2.1-with-dependencies.zip, 解压后有dist和lib两个文件夹里有Spring DM运行的jar包。

(2)在 Package Explorer 上右击,然后点击Import --> Plug-in Development --> Plug-ins and Fragments,然后单击下一步,将弹出Import Plug-ins and Fragments 对话框,选择Directory,然后加到spring-osgi-1.2.1-with-dependencies.zip解压后的文件夹,并进入dist目录,然后点击next,将以下三个插件添加到你的“Plug-ins and Fragments to import”中:

 

以下是引用片段:
 
org.springframeork.osgi.bundle.core
  org.springframeork.osgi.bundle.extender
  org.springframeork.osgi.bundle.io

      现在单击完成。Eclipse会将这三个套件导入到你的工作空间中,在那里你应能够在Package Explorer视图中看到它们。

(3)再将spring-osgi-1.2.1-with-dependencies.zip解压包里的lib目录下导入Plug-ins and Fragments to import,选择以下插件:

 

以下是引用片段:
  org.springframeork.bundle.spring.aop
  org.springframeork.bundle.spring.beans
  org.springframeork.bundle.spring.context
  org.springframeork.bundle.spring.core
  org.springframeork.bundle.spring.jdbc
  org.springframeork.bundle.spring.tx
  org.springframeork.osgi.aopalliance.osgi

      它们也加入到Package Explorer视图中。

    (4)打开Run configurations,在OSGI Framework里新建一个运行平台,并将它名字改为springDM,选择四个我们写的bundles和上面导入的spring依赖bundles,然后点击Add Required Bundles,就可以添加入有依赖其它bundles而没有引入的bundle,最后点击Validate Bundles来最后确认依赖包加全了没有,提示No problems were dected.便可以运行了。

 

(5)运行之后,我们发现控制台输出结果:
The Sum is---11
通过ss命令,如下:
5 ACTIVE      osgi.example.compute.multiply_1.0.0
6 ACTIVE      osgi.example.compute.add_1.0.0
7 ACTIVE      osgi.example.compute.client_1.0.0
将6停掉:stop 6
然后再refresh 7,控制台输出如下结果:
The Multiply is---30
通过 ss 命令,如下:
5 ACTIVE      osgi.example.compute.multiply_1.0.0
6 RESOLVED    osgi.example.compute.add_1.0.0
7 ACTIVE      osgi.example.compute.client_1.0.0
现在multiply处于运行状态,而add已经被停止,所以client导入的服务实际是由multiply提供的。

 

 

 

 

4. 总结

 

通过该文档,我们已经清楚了,如何使用Spring DM导出、导入服务。Spring DM的一些高级特性请查阅spring dm reference。

分享到:
评论

相关推荐

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java开源包10

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包8

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包1

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包11

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包2

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包3

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包6

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包5

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包4

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包7

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包9

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    java开源包101

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

    Java资源包01

    GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet....

Global site tag (gtag.js) - Google Analytics