随笔-1  评论-9  文章-7  trackbacks-0

        在读本文之前,您应该对基于Equinox的开发有一定的了解,如果您还不太清楚,请参考基于Equinox开发HelloWorld一文。
        
        本文讲到的例子是仿照网上甚为流行的一个例子,但苦于一直未找到源码,网上贴的都是一些转帖,代码片段,估计初学者很难将其还原并调通!我最开始弄这个咚咚的时候,其过程之痛苦,难以言喻,所以想着仿照该例子的设计,给予实现,文后贴出源码,希望能帮到大家。
        该例子是一个关于计算器的实例,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的动态服务调用能力。

1.   bundle osgi.example.compute 
      compute bundle只提供一个接口——Compute,因此无需依赖更多的bundle,只需最基本的osgi即可。因为不涉及注册资源之类的,所以也无需Activator入口类。
Computer接口源代码如下所示:

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当中,解决了开发时期的类型识别问题。
这样一来,在add bundle中就能使用compute bundle中的接口了,Computer接口的实现如下:

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

<?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的服务了,spring dm将通过一定的服务查找策略,返回匹配的服务。

3.    bundle osgi.example.compute.multiply

该bundle和add bundle相似,在这就不赘述了。
4.    bundle osgi.example.compute.client

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

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(
56));   
    }
   
}
  

      另外,因为client用到了其他几个bundle的类型,所以需要导入相应的包,步骤在上面已有讲到。
      spring dm靠<reference>元素来引入服务,最简单的形式如下所示:

<reference id="beanToPublish" interface="com.xyz.MessageService"/>  

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

<bean id="referenceBean" class="com.nci.ReferenceBean">   
    
<property name="messageService" ref="beanToPublish"/>   
</bean>  
      reference元素还有一些高级属性,详情请见spring dm reference。
     看一下client的spring配置文件:
<?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支持基于类的导出、导入,但是还是建议尽量基于接口,应该记住面向接口编程的思想,以应对将来有可能发生的改变。

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。然后即可点击运行了。
       运行之后,我们发现控制台输出结果:
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提供的。

6. 总结 

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


附件:osgi.example.compute.rar

posted on 2010-03-28 17:36 Dreava 阅读(12041) 评论(9)  编辑  收藏 所属分类: OSGi

评论:
# re: Spring DM的开发示例 2011-02-21 10:50 | sgwood
有些受启发,谢谢!  回复  更多评论
  
# re: Spring DM的开发示例[未登录] 2011-05-10 13:26 | peter
期待有web开发的例子
QQ:404089478  回复  更多评论
  
# re: Spring DM的开发示例 2011-06-29 11:49 | 小郑
刚接触,我怎样用DM开发一个WEB项目呢?QQ:99134194  回复  更多评论
  
# re: Spring DM的开发示例 2011-12-14 15:51 | qchen
感谢分享  回复  更多评论
  
# re: Spring DM的开发示例 2012-10-29 17:33 | 南云
spring的bean声明配置文件和osgi发布文件应该分别放在两个文件中。。


分别是 模块-spring.xml 和 模块-spring-osgi.xml  回复  更多评论
  
# re: Spring DM的开发示例 2012-11-23 11:05 | laidianren
很不错,辛苦了。  回复  更多评论
  
# re: Spring DM的开发示例[未登录] 2013-01-23 22:11 | fly
不错啊 很好,跑成功了。  回复  更多评论
  
# re: Spring DM的开发示例[未登录] 2013-10-06 13:58 | xxx
中间配置<service>还是不懂。没看会。  回复  更多评论
  
# re: Spring DM的开发示例 2013-10-14 14:49 | Jaken.Cooper
运行前:
在window->preferences->plug-in development->Target Platform面板中
设置的根本不是那张图显示的,没有选择Pre-defined Targets的地方,
我的Target Platform里面只有 Running Platform(Active)这个列表
所以在OSGI Framework里面也选不了spring的组件

请问下,这种情况怎么解决啊?谢谢了

PS:我的PDE版本是3.7的  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: