您现在的位置是:蓝石榴 > 个人博客 > OSGI

个人博客

OSGi原理与最佳实践--Spring-DM简介

2014-09-11OSGI 6297
Spring-DM指的是Spring Dynamic Modules。Spring-DM的主要目的是能够方便地将Spring框架和OSGi框架结合在一起,使得使用Spring的应用程序可以方便简单地部署在OSGi环境中,利用OSGi框架提 供 的服务,将应用变得更加模块化。
1.简介

Spring-DM指的是Spring Dynamic Modules。Spring-DM的主要目的是能够方便地将Spring框架和OSGi框架结合在一起,使得使用Spring的应用程序可以方便简单地部署在OSGi环境中,利用OSGi框架提 供 的服务,将应用变得更加模块化。

2.环境搭建

可以从Spring的网站上下载最新的Spring-DM包,这里提供了with-dependencies和没有dependecies两个包的下载。

spring-osgi-1.1.2with-dependencies.zip【下载】

spring-osgi-1.1.2.zip【下载】

我们建议大家下载with-dependencies的这个包,这个包里面包含了Spring-DM依赖的其他的包。下载了这个Spring-DM包后,我们把压缩包中的dist和lib目录解压到硬盘上的某个目录,比如解压到C盘根目录下的spring-dm 目录中。那么我们会在C:\Spring-dm\dist目录下看到如图1-52 所示的内容。在C:\spring-dm\lib中看到如图1-53所示的内容。

下面把spring-dm的bundle导入到Eclipse中

我们首先导入spring-dm的包。打开Eclipse,选择Import…,在Import的对话框中选择Plug-ins and Fragments(见图1-54)。

然后在Import Plugin-ins and Fragments对话框中做如图1-55所示的设置。

我们要设置Plug-in Location,先设置为c:\spring-dm\dist,导入sprimg-dm的包。点击Next后,出现了让我们选择导入的Plugin界面(见图1-56)。

我们可以导入core、extender、io 三个Bundle。完成后,会在Eclipse的工作区看到如图1-57的显示。

我们直接在Run Configurations中选择这三个Bundle,并执行,会发现三个Bundle都是INSTALLED状态,如果我们启动Bundle,会报错,原因是我们没有加入这三个Bundle所依赖的Bundle。而这些Bundle,也就在c:\spring-dm\lib目录下。我们用和前面一样的方式来导入lib中所需要的Bundle。要导入的Bundle 是 com.springsource.org.aopalliance 、org. springframework.aop 、org.springframework.beans 、org.springframework.context 、org.springframework.context.support 、org.springframework.core。这个时候,在Eclipse的工作区看到的应该是如图1-58的显示。

在Run Configurations中选择目前导入的所有Bundle,然后再选择Target Platform 中的org.apache.commons.logging这个Bundle,运行。可以看到,所有的Bundle都是ACTIVE状态了(见图1-59)。

到这里就完成了环境的搭建。下面就来做一个基于Spring-DM的应用。

3.HelloWorld

先看一个简单的例子。在这个例子中将展示如何把一个Spring Bean展示成服务,以及如何把OSGi的服务注入到Spring的Bean中。在这个例子中,有两个Bundle,分别是HelloWorld Bundle和TimeService Bundle。这两个工程中都没有BundleActivator。在Bundle启动和停止的时候不用去做什么事情。先来看一下TimeService工程(见图1-60)。

可以看到,我们在TimeService 工程中定义了TimeService 接口和TimeService 的实现(TimeServiceImpl)。在这里,这样定义和实现并不是一个很好的做法,接口的定义应该放到一个单独的Bundle中,这里不过是为了示意,选择了一个简单的做法。TimeService接口和TimeServiceImpl类的代码很简单,我们不再介绍。这个工程最大的不同是在META-INF目录下有一个spring目录。这个目录中有两个文件,分别是timeservice.xml 和timeservice-osgi.xml。我们分别看一下这两个文件的内容。

timeservice.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean name="timeService"

class="org.osgichina.demo.timeservice.impl.TimeServiceImpl">

</bean>

</beans>

这个xml文件中定义了一个spring bean。这个和通常的spring的配置文件没有任何区别。

timeservie-osgi.xml

<?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">

<osgi:service id="osgiTimeService" ref="timeService"

interface="org.osgichina.demo.timeservice.TimeService">

</osgi:service>

</beans>

这里,我们看到了一个新的标签“<osgi:service>”,这个标签的含义是来定义一个osgi的service。这个service实现的接口是“org.osgichina.demo.timeservice.TimeService”,另外这个service引用的对象是“timeService”,也就是刚才我们看到的上一个配置文件中定义的Spring Bean。这样的一个配置,就可以把spring bean发布成一个osgi的service了。是不是很简单呢。

下面我们看一下HelloWorld工程(见图1-61)。

可以看到,HelloWorld文件中只有HelloWorldImpl这样一个Java文件,并且在META-INF下也躲了一个spring的目录,目录中有helloworld-osgi.xml和helloworld.xml文件。我们简单看下HelloWorld的代码。

public class HelloWorldImpl{

private TimeService timeService;

public TimeService getTimeService() {

return timeService;

}

public void setTimeService(TimeService timeService) {

this.timeService = timeService;

}

public void start(){

System.out.println("started at " + timeService.getCurrentTime());

}

public void stop(){

System.out.println("stopped at " + timeService.getCurrentTime());

}

}

可以看到,HelloWorld是一个简单的bean,在调用start和stop的时候会有日志的输出。

好,接下来看helloworld.xml文件。

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean name="hello" class="org.osgichina.demo.helloworld.HelloWorldImpl"

init-method="start" destroy-method="stop" >

<property name="timeService" ref="osgiTimeService"/>

</bean>

</beans>

可以看到,这个配置文件和普通的spring配置文件是一样的,定义了一个bean,以及init和destory的方法。并且注入了一个对象给timeService这个属性。下面,我们来看一下helloworld-osgi.xml。

<?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">

<osgi:reference id="osgiTimeService"

interface="org.osgichina.demo.timeservice.TimeService"/>

</beans>

注意,这里也多了一个新的标签“osgi:reference”,这个是对OSGi服务的一个引用。这里要定义一下接口名称,因为这是用来表示引用的服务的。现在,我想大家已经明白了如何用spring-DM来把一个spring bean发布为服务,以及如何引用一个OSGi服务作为bean的属性了吧。这里,可能大家有一个疑问是,如果timeService不是注入到spring bean里面,而是要在代码中获取这个服务,那该怎么办呢?很简单,我们只要通过BundleContext来获取这个服务就好了。服务的名字就是接口的名字,换句话说,对于这个例子中的timeService,我们通过下面的代码就能获得这个服务:

ServiceReference sf = context.getServiceReference(TimeService.class.getName());

TimeService ts = (TimeService)context.getService(sf);

到这里,例子已经完成了。在这里简单介绍一下这背后的实现。其实是spring 的extender这个bundle帮我们完成了服务的发布和注入的工作。这个bundle会寻找META-INF下spring目录中的所有xml,完成配置工作。当然,我们也可以在MANIFEST.MF文件中配置spring-dm用到的配置。而spring目录则是一个默认的约定。

很赞哦!(1237)