1. 开发环境的准备
现在的eclipse都已经包含了Equinox,无需单独下载。
下载最新版的Spring DM,Spring官方网站:www.SpringSource.org
2. 开发OSGi的HelloWorld应用程序
在这一节,我们将开发一个OSGi bundle,演示如何利用Equinox进行OSGi bundle的开发、运行及调试,为之后的示例做准备。
首先,新建一个Plug-in工程
下一步,注意选择目标平台,默认为Eclipse version *,将其改成Equinox,
之后按默认下一步即可,到最后一步时,无需根据模板创建工程,去掉默认的勾,点击完成
可以看到,eclipse为工程自动生成了一个Activator类,如下所示
- package helloworld;
- import org.osgi.framework.BundleActivator;
- import org.osgi.framework.BundleContext;
- public class Activator implements BundleActivator {
- /*
- * (non-Javadoc)
- *
- * @see
- * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
- * )
- */
- public void start(BundleContext context) throws Exception {
- System.out.println("Hello World!");
- }
- /*
- * (non-Javadoc)
- *
- * @see
- * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
- */
- public void stop(BundleContext context) throws Exception {
- }
- }
package helloworld; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext * ) */ public void start(BundleContext context) throws Exception { System.out.println("Hello World!"); } /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception { } }
有过eclipse插件开发经验的人应该很快就能明白,这就是该工程——实际上就是上一篇文章中所称的bundle在Equinox平台中的启动入口,相当于我们的熟悉的main函数,如果将该bundle运行到Equinox中,首先进入该bundle的是Activator的start方法,你可以将相关的服务、资源在该方法内完成向bundleContext的注册——文章后面会具体讲到相关内容。在运行期,如果想要该bundle停止运行,Equinox平台将调用Activator的stop方法,你可以在该方法内完成资源的注销等工作。
下面我们将要完成首次的Equinox运行,将向大家展现bundle到底是如何运行起来的。为helloworld选择运行方式
弹出对话框
在弹出的对话框中,新建一个OSGi Framework运行环境(双击OSGi Framework即可,这里为其取名Equinox),选中helloworld(1.0.0),然后点击右边的Add Required Bundles按钮,eclipse将自动选中运行helloworld的依赖bundle,如果有必要,可以点击右下的Validate Bundles验证按钮,验证程序正常运行所需的bundle是否都被选中,最后点击运行,回到控制台:
osgi> Hello World!
可以看到,之前在Activator的start方法中的输出语句已经被输出到控制台,我们可以通过命令ss查看Equinox的运行情况,可以看到一共运行了两个bundle,如下:
ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.3.R34x_v20081215-1030
1 ACTIVE helloworld_1.0.0
还记得之前讲到过的bundle的几种状态吧?helloworld已经运行起来了。
那么Equinox具体支持哪些命令呢?下表列出了主要的一些命令,如需查看更详细的命令清单,则可以在控制台键入help。
类别 |
命令 |
含义 |
控制框架 |
|
启动框架 |
|
停止框架 |
|
|
关闭、退出框架 |
|
|
立即退出,相当于 System.exit |
|
|
卸载所有 bundle(前提是已经shutdown) |
|
|
设置属性,在运行时进行 |
|
控制 bundle |
|
安装 |
|
卸载 |
|
|
启动 |
|
|
停止 |
|
|
刷新 |
|
|
更新 |
|
展示状态 |
|
展示安装的 bundle 和注册的服务 |
|
展示所有 bundle 的简单状态 |
|
s |
展示注册服务的详细信息 |
|
|
展示导入、导出包的状态 |
|
|
展示所有已经安装的 bundles 的状态 |
|
|
展示 bundles 的头信息,即MANIFEST.MF 中的内容 |
|
|
展示 LOG 入口信息 |
|
其它 |
|
在另外一个进程中执行一个命令(阻塞状态) |
|
和 EXEC 不同的是不会引起阻塞 |
|
|
促使垃圾回收 |
|
|
得到属性,或者某个属性 |
|
控制启动级别 |
|
得到某个 bundle 或者整个框架的start level 信息 |
|
设置框架的 start level |
|
|
设置 bundle 的 start level |
|
|
设置初始化 bundle 的 start level |
至此,我们已经成功的演示了helloworld,初步了解了OSGi的bundle是如何开发并运行的,下面将进入我们的正题,下面我们将通过一个稍微复杂的示例,讲解bundle之间如何进行包依赖、注册及调用服务
3. 开发一组计算器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接口源代码如下所示:package osgi.example.compute;
- public interface Compute {
- public String computeNums(int x, int y);
- }
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的时候发生问题。 |
通过引入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;
- }
- }
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"/>
<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>
<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类的实现很简单,如下所示:
- 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));
- }
- }
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>元素来引入服务,最简单的形式如下所示:
- <reference id="beanToPublish" interface="com.xyz.MessageService"/>
<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>
<bean id="referenceBean" class="com.nci.ReferenceBean"> <property name="messageService" ref="beanToPublish"/> </bean>reference元素还有一些高级属性,详情请见spring dm reference。
看一下client的spring配置文件,这里用osgi:reference标签来引用服务,上面的配置中用osgi:service标签来发布服务:
- <?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>
<?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。
相关推荐
标题中的“Spring与OSGI整合 计算器例子(转) +附整合代码和spring-osgi核心jar”表明我们将探讨如何将Spring框架与OSGi(Open Services Gateway Initiative)模块化系统进行集成,并通过一个计算器的例子来说明这个...
标题“spring-dm-osgi整合jar包”和描述“spring-dm整合osgi所需所有jar包”提及的核心知识点是Spring Dynamic Modules(简称Spring DM)与OSGi(Open Service Gateway Initiative)框架的集成。这两个技术在Java...
在这个案例中,我们将探讨如何整合OSGI、Spring、Mybatis以及Spring MVC来实现一个登录应用。这个教程旨在帮助开发者理解如何在OSGI环境中集成这些流行的Java技术,以构建灵活且可扩展的应用程序。 首先,我们需要...
标题 "RAP 整合 Spring(基于 Spring-osgi)" 暗示了本文将探讨如何在 RAP(Remote Application Platform)框架中集成 Spring 框架,并利用 Spring-osgi 进行服务管理和依赖注入。RAP 是一个用于构建富客户端应用...
本教程将详细讲解如何在Eclipse环境中构建一个整合了Spring和OSGi的项目。 首先,我们需要了解Spring框架。Spring以其依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)的...
在OSGI(Open Service Gateway Initiative)应用环境中,整合Spring、Mybatis和Spring MVC可以实现模块化、可热更新和高效的企业级应用开发。OSGI是一个Java框架,它允许动态地安装、卸载和升级服务,提供了强大的...
《Eclipse RCP与Spring OSGi:技术详解与最佳实践》由资源的Eclipse专家亲自...实战篇(第13-15章)详细讲解了Eclipse RCP与Spring OSGi框架、Hibernate ORM框架、JPA规范、Maven工具的整合,以及它与Java的模块化设计
为了深入了解OSGI与Spring的整合,阅读"OSGI入门和整合Spring.pdf"文档将是十分有价值的。这份资源可能会涵盖以上提到的所有知识点,通过实例和最佳实践帮助开发者熟练掌握这两种强大的技术的结合。
它放弃了传统的Java EE服务器标准,转而采用一套全新的基于OSGi内核的部署和打包系统,从而更加自然地整合了Spring编程模型。这种创新的架构不仅简化了应用服务器的配置和管理,同时也提升了应用的性能和稳定性。 #...
对于企业级应用,Spring动态模块与OSGI平台的整合能提供以下功能: 模块内部更好的应用逻辑分离 同时部署同一模块的多个版本 在系统中动态发现和使用模块提供的服务 在系统运行时动态安装,更新和卸载模块 ...
然而,需要注意的是,Spring DM在Spring 3.0之后被弃用,取而代之的是Spring OSGi,所以这个实例可能较旧,或者需要更新到现代的Spring Boot与OSGi结合的方式。 至于压缩包内的"整合代码原版",这可能是一个完整的...
将OSGI与Spring整合,可以充分利用两者的优点,构建更加灵活、可扩展且易于维护的系统。整合OSGI和Spring的主要目的是实现服务的动态发现和管理,以及在运行时动态装配和更新组件。 整合过程通常包括以下步骤: 1....
本资料集合涵盖了OSGI的入门、进阶以及实战应用,特别是与Spring框架的整合。 《OSGI进阶》着重介绍了OSGI的核心概念和技术细节,包括: 1. **模块系统**:OSGI基于JAR文件作为模块的基本单位,每个模块都有自己的...
Spring OSGi 与 Spring 框架的整合 - **Bean 容器**: Spring OSGi 使用 OSGi 服务作为 Spring Bean,实现服务的动态发现和依赖注入。 - **配置管理**: OSGi 服务注册表可以被 Spring 配置,允许 Spring 配置动态...
#### SpringDM+OSGI整合挑战 最后,我们来看看如何将SpringDM与OSGI结合使用,并解决其中遇到的一些问题。 1. **版本冲突**:在整合过程中,可能会遇到版本不兼容的问题。例如,SpringDM中的`org.springframework....
总结,"基于osgi整合ssm框架注解开发"的主题涵盖了使用OSGi的模块化特性来管理和部署基于Spring、SpringMVC和MyBatis的Web应用,同时利用注解简化配置和开发过程。通过这样的整合,开发者可以构建出高度可扩展、模块...
在本文中,我们将深入探讨如何基于VirgoServer进行Spring Osgi Web开发,这是一个涉及OSGi容器、Spring框架和Web应用程序的集成技术。首先,我们需要确保拥有正确的开发环境和工具,包括Spring Tool Suite (STS),...