OSGI进阶:第五章 将原系统重构为基于OSGi的系统

 由  ValRay 发布

5. 将原系统重构为基于OSGi的系统

在看完以上的章节后,希望能让大家在新的项目/产品无所顾忌的使用 OSGi,但对于已存在的项目/产品而言,怎么办呢,因为像产品而言的话,通常都是经历过一段很长时间的发展的,不可能抛弃以前所有的努力,因此还得有将原系统重构为基于 OSGi 的系统的方法。 在这个章节中将把一个传统的基于hibernate+spring+webwork搭建的留言板系统重构为可部署至OSGi框架中的系统,重构时的原则是尽量不去修改原代码,基于BND(Bundle Tool) 直接创建符合OSGi规范的Bundle进行部署,从而实现重构。 先来看看传统的留言板系统的工程,工程目录示意如下:

此留言板系统实现了之前例子中的留言板的列表显示和新增留言的功能,重构需要达到 的 目 的 就 是 区 分 出 留 言 列 表 显 示 模 块 和 新增留言模块 , 并部署至 (OHSW)OSGi+Hibernate+Spring+Webwork 的脚手架中,终的效果则需和传统的单工程部署至 tomcat 等应用服务器的效果一致。 为了尽量不改变现有工程的结构和代码,而又要达到部署到(OHSW)的脚手架中去,需要做到的就是结合现有的代码来创建符合 OSGi 规范的 jar 文件,BND 可以起到这个作用,因此选择了 BND 来实现重构的需求。

5.1. 重构

BND 根据一个 bnd 的描述文件来生成 bundle 的 jar 文件,根据之前对于留言板系统的设计,我们需要将留言列表模块和新增留言模块作为分开的两个 bundle 进行打包生成 jar,同时还需根据(OHSW)的脚手架中的要求来部署 po、action 和 spring bean。

留言列表模块 首先根据设计确定留言列表模块需要包含目前工程中哪些 package:

cn.org.osgi.bulletin.list.action cn.org.osgi.bulletin.list.pages 

cn.org.osgi.bulletin.po cn.org.osgi.bulletin.service 

cn.org.osgi.bulletin.service.impl

接下来分析这些 package 哪些是需要对外 export 的,根据设计,留言列表模块中 没有需要对外 export 的 package。 在对 package 分析完毕后,来分析有哪些资源文件是此模块需要的,Action 的配 置文件、Spring bean 的配置文件、Hibernate.cfg.xml 这些是需要根据 OHSW 脚手 架的要求来稍作修改,因此没有需要直接绑定到留言列表模块 jar 文件的资源文 件。

在完成了上述的步骤后,需要根据 OHSW 脚手架的要求来注册留言列表应用、 注册 webwork action、注册 PO、引用 Hibernate 模块的 CommonDaoService 实现 持久化操作以及对外发布 Action 服务。 注册留言板列表应用 按 照 OHSW 脚 手 架 的 要 求 , 注 册 留 言 板 列 表 应 用 需 通 过 WebworkModule.ControllerExtension 扩展点来实现,在现工程上增加一个 bulletinlist 目录,在该目录下新建 plugin.xml 文件,在其中加上如下内容:

<extension 
    
point="WebworkModule.ControllerExtension">


这样也就完成了留言板列表应用的注册了。

注册 webwork action

根据 OHSW 脚手架的要求,webwork Action 配置文件的编写方法稍有不同,主要是在 action 的 class 这个属性值上,需要改为 Action 服务对应的 command 属性值(如之前 Action 配置文件不是按模块编写的,现在则需改为按模块来 编写为独立的 Action 配置文件):

package name="bulletin-list" extends="webwork-default" namespace="/bulletin">


/cn/org/osgi/bulletin/list/pages/list.vm

Action 的注册通过 WebworkModule.ActionExtension 扩展点来实现,打开之前的 plugin.xml,在其中加入如下内容:

<extension         point="WebworkModule.ActionExtension">

注册 PO

根 据 OHSW 脚 手 架 的 要 求 , PO 的 注 册 通 过 HibernateModule.HibernateExtension 扩展点来实现,打开之前的 plugin.xml, 在其中加入如下内容:

<extension point="HibernateModule.HibernateExtension">

引用 Hibernate 模块的 CommonDaoService 实现持久化操作 持久化操作可引用 Hibernate 模块的 CommonDaoService 来实现,如要改为引用 CommonDaoService,需在现工程的 build path 中增加对于 Hibernate 模块 的引用,如之前是直接引用的封装 Hibernate 模块的 jar,现在则需要改为通 过 Spring-OSGi 的配置方式来引用 Hibernate 模块提供的 CommonDaoService 的 OSGi 服务:



同时需要删除bulletinListService bean配置中通用Dao服务的注入。 这样的改动会引起需要修改 bulletinListService,需要在其中加上 setCommonDaoService和unsetCommonDaoService这两个方法,在改成这种情况下,需要注意CommonDaoService可能会随时变为null,所以要做好防 止调用CommonDaoService出现NullPointerException的处理。 对外发布 Action 服务 Action 服务需要对外发布,由于 Action 的定义之前是在 spring bean 配置,而现在这个 Action 还需要对外提供接口为 cn.org.osgi.xwork.action.IAction 的 OSGi 服务,在此借助 Spring-OSGi 来实现,在 spring bean 的配置文件中加上如下内容:



LIST

这同样会引起bulletinListAction的修改,需要在该类上加上对于IAction 接口的实现。 在完成了上面这些配置文件的编写和代码的部分修改后,就可以开始编写留言列表模块BND文件的编写了。 在BND文件中需要描述模块的信息,如Bundle名、版本、私有的Package、对外 Export的Package、需要包含的资源文件、需要的Bundle等等。

按照留言列表模块的设计以及 OHSW 脚手架的要求,后形成的留言列表模块的 bnd文件内容如下所示:

Bundle-Name: BulletinList Module 

Bundle-SymbolicName: BulletinListModule;singleton:=true 

Bundle-Version: 1.0.0 

Bundle-Vendor: OSGi.org.cn

#需要包含至此Bundle的package,但不对外Export Private-Package: cn.org.osgi.bulletin.list.,cn.org.osgi.bulletin.po,cn.org.o sgi.bulletin.service. Require-Bundle: org.eclipse.equinox.registry,org.eclipse.equinox.common,Webw orkModule

#多数需要Import的package bnd都会自动的识别出来,确实有需要的话也可以 手工在这里指定

Import-Package: !org.eclipse.core.runtime,org.eclipse.equino

x.http.registry,org.osgi.framework,*

Export-Package:

cn.org.osgi.bulletin.list.action;-noimport:=true,cn.org.osgi .bulletin.list.pages;-noimport:=true,cn.org.osgi.bulletin.po ;-noimport:=true

# 需要包含的资源文件,plugin.xml 中有扩展点的描述,spring 目录下放置了 spring bean 的配置文件,下面的配置的意思是把 spring 目录下的文件打包到 META-INF/spring目录下

Include-Resource:   plugin.xml=bulletinlist/plugin.xml,

META-INF/spring=spring

在编写完上面的bnd文件后,就可以在Eclipse中选中这个文件,右键,选择其中的Make Bundle(前提是先安装bnd的eclipse插件),就可以生成留言列表模块的jar文件了。 在生成了这个jar文件后,就可以启动OSHW的脚手架了,启动完毕后在console通过install file:///这样的方式把jar文件安装到脚手架中,安装完毕后通过 start的方式启动留言列表Bundle,通过web方式访问即可看到和传统的留言板系统同样的留言列表了。 新增留言模块 新增留言模块和留言列表模块的 bnd 打包过程基本一致,不同的地方在于留言列表模块采用 Spring-OSGi 的方式实现注入和 OSGi 服务的引用、发布,新增留言模块则直接使用 OSGi 的 DS 方式实现,在 bnd 描述文件中可采用以下的方式来 描述 OSGi Service 和 Component:

Service-Component: cn.org.osgi.bulletin.add.action.NewBulletinAction;properties:="command=NEWBUL LETIN";

provide:="cn.org.osgi.xwork.action.IAction",cn.org.osgi.bulletin.add.action.S    aveBulletinAction;properties:="command=SAVEBULLETIN";

service=cn.org.osgi.mo dule.hibernate.service.CommonDaoService;provide:="cn.org.osgi.xwork.action.IActio n";dynamic:="service"

根据这样的描述,bnd 在进行打包生成 jar 文件时将会自动生成 ds 的描述 xml 文件。 新增留言模块终形成的 bnd 文件内容如下所示:

Manifest-Version: 1.0 

Bundle-ManifestVersion: 2 

Bundle-Name: NewBulletin Module 

Bundle-SymbolicName: NewBulletinModule;singleton:=true 

Bundle-Version: 1.0.0 

Bundle-Vendor: OSGi.org.cn 

Include-Resource: plugin.xml=newbulletin/plugin.xml 

Service-Component:

cn.org.osgi.bulletin.add.action.NewBulletinAction;

 properties := "command=NEWBULLETIN";provide:="cn.org.osgi.xwork.action.I     Action",cn.org.osgi.bulletin.add.action.SaveBulletinAction;p    roperties:="command=SAVEBULLETIN";service=cn.org.osgi.module .hibernate.service.CommonDaoService;provide:="cn.org.osgi.xw ork.action.IAction";dynamic:="service" 

Export-Package: 
cn.org.osgi.bulletin.add.action;-noimport:=true,cn.org.osgi.

bulletin.add.pages;-noimport:=true

选择此BND文件,运行Make Bundle,生成新增留言模块的jar文件。 按照留言列表模块同样的方式install到OHSW脚手架中,此时留言列表显示以及新增留言功能均可正常使用了,效果和传统的基于Hibernate+Spring+Webwork的留言板系统完全一致,并且工程和代码结构也基本相同。

经过以上这些步骤,就实现了将传统的基于Hibernate+Spring+Webwork的留言板系统部署到基于OHSW的脚手架中了。

5.2. 小结

总结整个重构的过程,在重构时需要做的主要是:

找出模块所需的 package

确定模块对外 Export 的 package 以及 OSGi 服务、需要引用的 OSGi 服务 确定模块所需包含的资源文件 按照脚手架的要求编写必要的文件,对原有代码进行一定的修改 从章节中示例的留言板系统的重构来看,似乎没碰到多大的阻力,这是因为这个原有的留言板系统在实现时是比较严格的遵守了模块化的,因此在重构时定义出模块的 package、对外 export 的 package 以及 OSGi 服务时都能很容易的完成。

总的来说,要将原有系统重构为可部署至 OSGi 的系统,还是比较的困难和麻烦的,决定性的要素主要是以下三个方面: 模块化 只有在重构进行的时候才会确定以前的系统是否真正的做到了模块化,如果之前的系统做的不够模块化的话,在重构的过程中将会比较的麻烦,会涉及到修改原工程的结构和原代码。 模块化的部署能够改善原系统的设计,使得每个模块的闭合性和耦合性变得更加的清晰。 如果想确定原有的系统是否足够的模块化的话,将它重构部署至 OSGi 是个不错的判断方法。 保持动态性 这点呢,是由于部署至 OSGi 框架而带来的,例如之前通过 spring 注入的 bean,现在这些 bean 有可能是位于其他模块中的,这就需要通过以 OSGi 服务的方式进行注入,同时需要注意 OSGi 服务是动态性的,也就是说注入的服务可能随时变得可用,也有可能变得不可用,因此在代码中需要注意这种动态性,避免由于服务的动态性造成系统的错误。 当然,这步重构不做也是可以,不过这一定程度上就发挥不出部署至 OSGi 的优势了。 改为使用 OSGi 服务的方式来引用其他模块提供的功能,能够很大程度的提升系统的灵活性,并且一定程度上能够强制面向接口的执行。 即插即用 即插即用是部署至 OSGi 的应用应追求的目标,像上面传统的留言板系统中的留言列表页面上的新增留言链接,就是个典型的非即插即用的例子,因为这个新增留言的链接应该是跟随新增留言模块而产生的,可以想像,当新增留言模块不存在时,那么新增留言链接存在是没有意义的,基于 OSGi 的应用应保证当新增留言模块安装了后才会相应的出现新增留言的链接等,也就是要切实的保证模块的独立性和即插即用,不能像新增留言链接这种造成模块的强耦合。 而这点呢,也是将原系统重构为 OSGi 应用中麻烦的一步,这通常来讲会需要重构之前的设计来实现。 只有在上面三点都做到的情况下,才能说原有系统成功的重构为了 OSGi 应用。


wmz 2016-07-22 17:25

http://osgi.org.cn 翻译启动,欢迎投稿。

顶(0) 踩(0) 回复
查看评论