作为一个新的事实上的工业标准OSGi 已经受到了广泛的关注 其面向服务(接口)的基本思想和动态模块部署的能力 是企业级应用长期以来一直追求的目标Spring 是一个着名的 轻量级 JEE 开发框架其特点是面向接口编程和非侵入式的依赖注入将 OSGi 和 Spring 结合能充分发挥二者各自的特长更好地满足企业级应用开发的需求Spring 开发组织在 年发布了将 OSGi 和 Spring 结合的第一个版本SpringDM本文通过一个简单实例介绍如何利用 SpringDM 开发基于 OSGi 和 Spring 架构的 Web 应用同时探讨其中用到的关键技术及其基本思想
开发一个简单的OSGi Web应用实例
一个简单的 Web 应用
我们写一个简单的 Web 应用 l 计算两个数字的和或乘积如下图所示
图 一个简单例子
为了体现 OSGi bundle 的动态部署能力我们写两个 service bundle其中一个计算两个数字的和(称为 add bundle)另外一个计算两个数字的积(称为 multiply bundle) 当我们点击Compute按钮的时候如果此时 add bundle 被部署则页面将返回两个数字的和否则如果此时 multiply bundle 被部署则页面将返回两个数字的积开发环境准备
下载 Eclipse
获取所有 OSGi Equinox 和 Spring 的插件 如下图所示:
打开 Eclipse 设置 target platform 为上述插件集合
基本模块设计
该应用主要包含两个层次: 服务层和 Web 层Web 层基于 SpringMVC 实现包含处理 Web访问相关的 bundle(本例中只有一个)服务层包含处理数字计算的 bundle本例中包含一个声明服务接口的 compute interface bundle 和两个实现该服务接口的 bundle add bundle 和 multiply bundle基本模块结构如下图所示
图 基本框架
模块程序实现
Step 实现 Service Layer
服务层的三个 OSGi bundle 实现完毕之后如下图所示
图 服务层
其中 comzxnpute 是声明服务接口的 bundlecomzxnputeadd和comzxnputemultiply 是实现了服务接口的两个 bundle
zxnpute
声明一个 Compute 接口其中包含一个接口方法 computeNums()如下图所示
图 服务层接口 bundle
zxnputeadd
bundle comzxnputeadd 的基本程序结构如下图所示
图 接口实现 bundle add
在该 add bundle 中添加一个Add类实现Compute接口如下图所示
图 接口实现代码 Add 类
注意到我们在 METAINF 下建了一个 spring 目录并且添加了一个 computeAddcontextxml 文件系统启动时Spring 将利用该xml文件创建一个 bean 实例并把该 bean 输出为一个 OSGi service如下图所示
图 Spring 声明文件 computeAddcontextxml
该xml文件中osgi : service是 SpringDM 输出 OSGi service 的标记其中的 interface属性标明了该 service 实现的服务接口
zxnputemultiply
按照与add bundle 同样的方法实现 multiply bundle如下图所示
图 接口实现代码Multiply 类
类似的添加一个 computeMultiplycontextxml 输出 OSGi service如下图所示
图 Spring 声明文件computeMultiplycontextxml
Step 实现 Web Layer
Web 层只包含一个 bundlecomzxnexampleweb采用 SpringMVC 和 OSGi 构建基本程序结构如下图所示
图 Web Layer 程序结构
ComputeControlerjava
该JAVA类实现了 orgspringframeworkwebservletmvcController是本 web应用中核心的 servlet负责接受并处理 web 请求该类调用 ComputeServiceRef 的方法实现业务逻辑该类关键的方法是 handleRequest(…) 如下图所示
图 核心 servlet 类
ComputeServiceRefjava
该 JAVA 类负责引用部署的 service bundle 完成最终计算其中的 computeService 由 Spring 根据 OSGi 中实际部署的 service 进行注入本例中实际部署的 service 可能是 add bundle 或者 multiply bundle
需要特别注意的是此处体现了 SpringDM 的动态特性OSGi 的动态部署能力使得 Spring 的动态服务注入成为可能
图 服务消费类
HTTPContextResgistryjava
该 JAVA 类负责在 OSGi 环境中配置和注册 HTTP 服务其关键方法为 bean 初始化时调用的 init( ) 方法
图 在 OSGi 环境中注册 HTTP 服务
该 init 方法中第六行的 getHTTPService(…) 调用 OSGi 的 ServiceTracker 来获取 OSGi环境中注册的 HTTP 服务的引用如下图所示
图 使用 ServiceTracker 获取 HTTP 服务
computeWebcontextxml
该 xml 文件主要用于配置 HTTPContextResgistry bean 类以及导入对 Compute 服务接口的引用标记 osgi : reference 用于声明要导入的服务接口其 interface 属性标明了该接口的定义本例中为 comzxnputeCompute 接口
图 Spring 声明文件导入服务接口
computeWebDispatcherxml
该 xml 文件用于配置 ComputeControler bean类
图 Spring 声明文件配置核心 servlet 类
运行程序 以往开发 JEE 应用通常需要将应用服务器的 runtime 集成到开发环境中才能进行程序调试非常麻烦基于 OSGi 的应用完全可以脱离应用服务器运行这使得程序开发和调试变得非常容易直接在 Eclipse 中调试运行就可以我们在 Eclipse 中将程序运行起来如下图所示
图 运行 OSGi 程序
从上图中看到我们同时选择部署了 add bundle 和 multiply bundle利用 OSGi console 察看如下
图 察看部署的 OSGi bundle
当 OSGi 环境中同时部署有多个服务接口的实现 bundle 时OSGi 会选择一个默认的 bundle提供服务本例中Spring 会默认注入 add bundle我们通过 web 访问 l 页面
图 访问页面
点 Compute 按钮之后结果页面如下
图 访问结果
可以看出是 add bundle 提供了计算服务下面我们通过命令 <stop > 来停止 add bundle的服务
图 停止 add bundle
图 add bundle 状态变为 RESOLVED
重新访问 l 页面结果得到的是两个数字的乘积可以看出是 multiply bundl
提供了计算服务如下图所示
图 再次访问页面
小结
作为当前颇具生命力的两个标准和框架OSGi 和 Spring 已经初步融合在一起二者的结合为开发企业级的 Web 应用同时提供了巨大的灵活性和动态部署能力本文通过一个简单的例子描述如何开发一个基于 OSGi 和 Spring 的 Web 应用并说明了开发过程中涉及到的技术关键点