`

OSGi动态化深入分析

    博客分类:
  • OSGI
阅读更多

OSGi最吸引人的特性除了模块化之外,就是动态化了,在我之前写的OSGi实战以及进阶两篇Opendoc中,都有相关的示例,但不知道大家有没有注意,在两篇Opendoc中都未提及到bundle本身的更新,而基本都是以新增服务实现的bundle以及停止服务时限的bundle为例,并且相对而言是个比较简单的例子,动态化在java界更明确的词也许是hot deployment,而hot deployment的实现并不容易,同样,即使你采用OSGi,但也不代表你的应用就具备了hot deployment的能力,在hot deployment上,完美的结果就是当更新完成后,新的执行请求就在新的代码逻辑上正确的执行,就像没发生过更新这回事样,但实际要做到这样的效果,远没这么容易,即使是基于OSGi也同样如此,No magic & no silver bullet,在本篇blog中我们就来具体的看看。

  OSGi以Bundle为粒度来实现动态化,也就是说,如果要更新一个类,需要做的是更新整个Bundle,虽然比直接部署一个类麻烦了点,但也还算是不错的了,更新的方法有两种,一种是直接update该bundle(在MANIFEST.MF中增加Bundle-UpdateLocation来指定Bundle更新时所使用的文件);另外一种是先uninstall旧的bundle,然后再安装并启动新的bundle,无论是哪种方法,对于OSGi的应用而言,问题就在于package的类的改变以及bundle中OSGi服务实现的改变。

  在Equinox中,当update一个Bundle时,如果这个Bundle中有对外暴露的package,如果这个Bundle是singleton模式,在update后仍然保留了同样的Bundle SymbolicName的话,其实是无法update成功的,会报出一个已经有相同的Singleton的Bundle存在,因此update这种方法仅适用于没有对外暴露package的bundle,如bundle没有对外暴露的package,Equinox则可正常的完成update过程,通常来讲,不对外暴露package的bundle都是一些对外暴露OSGi服务或者使用OSGi服务的类,对于对于暴露OSGi服务的类而言,在update过程中将会把依赖了此OSGi服务的OSGi组件的实例销毁(递归),等当前bundle更新并启动完毕后,会重新实例化该OSGi组件,同时将新的服务实现对象设置进去,对于仅使用其他Bundle提供的OSGi服务的类而言则很简单了,在启动此bundle时自然会设置进来,同时也不会影响外部bundle。

  从上可见,通过update方式来完成Bundle的更新受到了很大的限制,毕竟大部分时候Bundle都是singleton的,并且在更新的时候也是不会去改变其Bundle SymbolicName。

  因此,在Equinox中要实现Bundle的更新,通常都使用另外一种方法,就是uninstall,然后再install并start更新后的bundle。

  当uninstall时,如果此bundle有对外暴露的package,并且有使用这些package的bundle,那么Equinox会保留此Bundle的classloader,也就是说原来使用了这些package的bundle仍将使用之前bundle的类,这也是为什么一个Bundle uninstall了之后,其他Bundle仍然可使用该Bundle中export的类,要想让Bundle对外export的package的引用也失效并且切换到新的bundle中export的package,必须执行refresh动作,refresh时equinox将会找到之前uninstall没完全成功的bundle,并递归找到使用了这个bundle中package的bundle,将这些bundle的状态也置为unresolve,并解除对之前uninstall没完全成功的bundle的classloader的引用,这样被uninstall的bundle的class就能被GC卸载了,在此之后,Equinox会尝试再次去resolve之前设置为unresolve的bundle,如果resolve不了则会调用这些bundle的stop方法,卸载其对外提供的OSGi服务以及引用的OSGi服务,同时将其状态置为INSTALLED;但在uninstall时,对OSGi服务的处理方法则不太一样,此Bundle中所引用的OSGi服务会被释放,对外提供的OSGi服务也会注销,这会造成引用了这些OSGi服务的Bundle的OSGi组件(递归)的实例会被销毁。

  完成了以上的动作后,可以安装新的bundle,安装新bundle时,其实就是做了些解析bundle的事情,直到start bundle时,才开始resolve过程,所谓resolve就是找到bundle对外提供的package、需要引用的package等,同时创建bundle的classloader,在这个过程,equinox也会对系统中所有unresolved的bundle进行resolve,如能够resolve则将其状态转化为resolved,最后调用BundleContext的start来完成bundle的启动,这个过程仅仅是在配置了BundleActivator的情况下才有意义,DS则完成此bundle中引用的OSGi服务或对外提供OSGi服务的组件的条件的检测,以判断这些组件是否可实例化,如有新的OSGi服务可对外提供,那么DS会检测此时其他Bundle中的OSGi组件是否需要被激活,或者是否需要调用其他Bundle中OSGi组件的set方法。

  根据以上这样的描述,可以看出,在OSGi中如果要更新没有对外提供package的Bundle是比较容易的,update以及uninstallàstart都是可选的方法,而对于对外提供了package的Bundle而言,则相对复杂很多,只能选择uninstallàrefreshàstart来完成。

  从两个纬度来看OSGi的动态化,对于有export-package Bundle的更新,OSGi将会重建更新的bundle以及引用了此bundle的package的ClassLoader,而对于OSGi服务组件的更新,OSGi则会重新创建引用了此OSGi服务的组件的实例,并通过unset这样的方法通知原来的组件释放对OSGi服务的引用,同时通过set方法来给新创建的实例注入更新后的OSGi服务组件实例,其实这也是hot deployment中常见的对于引用变更的处理方法。

  但从上面也可以看出,OSGi并没有提供对象状态保留的处理,这也就意味着,基本上在一次更新后,此次更新的Bundle以及相关的bundle因为classloader的重建,其对象的状态数据都丢失了,不过对于更新的仅为提供或引用OSGi服务的Bundle而言,则稍微好点,毕竟只是影响到了递归的引用了OSGi服务的组件,组件由于重建实例,而导致状态数据丢失,这个倒是可以通过将服务的引用数量设置为cardinality=”0..1”或cardinality=”0..n”来解决,设置成这样的条件后,即使引用了需要更新的Bundle中提供的OSGi服务,其OSGi服务组件实例也不会被重建,这对于需要将OSGi服务引用提供给外部使用的系统而言,无疑非常有帮助。

  根据以上所述,可以看到,即使是基于OSGi,要实现hot deployment还是比较麻烦的,No magic and no silver bullet,J,尤其是要注意classloader的重建以及OSGi服务组件实例的重建,否则很有可能会造成在更新后系统的异常,在基于OSGi实现hot deployment时,要合理的规划系统,常见的一些较好的实践方法有:

  l 接口和实现分离

  避免因为实现逻辑要更新,而造成其他引用了此Bundle export出去接口所在的package而导致classloader的重建。

  l 对于需要保留状态数据的OSGi服务尽量避免引用其他bundle export-package中的类

  这也是为了避免这些类所在的bundle的classloader重建,毕竟OSGi服务组件类可以通过设置cardinality来保持组件实例的不变。

  l 服务组件采用cardinality=”0..1”或cardinality=”0..n”来设置对OSGi服务的引用

  避免服务组件实例的重建,毕竟这是个递归过程,影响还是很大的,而且谁也不敢肯定这么多的服务组件实例的重建是不是会造成系统的异常现象。

  在这种情况下,尤其要注意unset中的处理以及当没有可用服务情况下的处理,避免出现NPE。

  l 尽量采用OSGi服务组件服务方式,而不是直接的类方式

  由于类方式的更新成本实在是比较的高,毕竟那需要classloader的重建,但是有些类确实是没办法的,对于这些类要尽量的保证稳态。

  l 严格的版本控制

  毕竟接口的更新影响是很大的,因为所有实现接口的类都得改变,因此需要严格的制定版本规范,并在引用package时按照版本规范指定相应的版本范围。

分享到:
评论
1 楼 wh176781788 2011-08-31  
写的不错

相关推荐

    osgi插件化开发流程

    osgi插件化开发流程

    OSGi原理与最佳实践

    其后进入OSGi实战,结合实例讲解如何基于OSGi框架编写模块化、动态化的各种Java应用;最后对OSGi知识进行深入讲解,通过对OSGi规范和实现框架(Equinox、Felix、Spring-DM和Apache CXF)的分析,以及最佳实践的介绍...

    OSGI原理最佳实践(包含源代码)

    是一本适合新接触OSGI开发学习的一本很好的书,本书介绍了Equinox, Spring-DM和Felix这三个常用的OSGi容器的使用、...本书适合希望了解、深入掌握OSGi,以及编写模块化、动态化Java应用的Java架构师和开发人员阅读。

    OSGI原理与最佳实践

    资源名称:OSGI原理与最佳实践内容简介:国内第一本...其后进入OSGi实战,结合实例讲解如何基于OSGi框架编写模块化、动态化的各种Java应用;最后对OSGi知 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。

    OSGi原理与最佳实践(精简+完整版)

    本书从OSGi 的简介开始,到OSGi 框架的使用,再到OSGi规范的掌握,最后到OSGi框架的实现分析,阐述了基于OSGi编写模块化、动态化的Java 系统须要掌握的知识体系,希望此书能给读者带来一次愉快的OSGi之旅。

    osgi介绍osgi介绍

    osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍

    OSGi动态部署案例

    主题项目可以动态识别观察者的添加和删除,当添加或删除观察者时,不需要对原有的项目进行修改或重启容器.rar

    基于OSGI的Java中间件分析和设计

    OSGi有多种(开源)实现,如Equinox、Apache的Felix和Knoflerfish以及ProSyst推出的世界上最小的嵌入式OSGi等

    深入理解OSGi:Equinox原理、应用与最佳实践.pdf

    深入理解OSGi:Equinox原理、应用与最佳实践.pdfOSGi应用开发

    基于OSGi的轻量级动态化系统研究

    提出基于OSGi框架和插件设计模式结合,构建可扩展轻量级动态化系统的方法

    OSGi与Equinox 创建高度模块化的Java系统

    第四部分呈现了动态性的最佳实践、整合代码库等主题以及一些OSGi和Equinox难题,帮助读者全面理解如何创建高度模块化系统。 《OSGi与Equinox:创建高度模块化的Java系统》适合有Java编程基础以及对OSGi技术有兴趣的...

    Eclipse-OSGi内核源码分析

    本书能帮助堵住深入了解 OSGi技术,本书深入分析描述了 OSGi的各种源码。

    OSGi_动态服务

    教你如何实现osgi服务 如何在_WebSphere_Application_Server_V8_中实现_OSGi_动态服务功能

    OSGI原理与最佳实践(扫描版,带目录).pdf

    其后进入OSGi实战,结合实例讲解如何基于OSGi框架编写模块化、动态化的各种Java应用;最后对0SGi知识进行深入讲解,通过对0SGi规范和实现框架(Equinox、Felix、Spring—DM和Apache CXF)的分析,以及最佳实践的介绍,...

    深入理解OSGi Equinox原理、应用与最佳实践

    osgi模块化思想还是蛮值得学习的,热插拔的想法也挺好。

    使用OSGi构建模块化云应用

    应对变更是构建应用程序要解决的基本问题之一。这并不一定很难,因为处理软件并不受什么物理法则的限制。变更是一个架构层面的问题,但不幸的是这一点经常被忽视。某种程度上这是符合逻辑的,因为多数时候你看不到...

    domino:轻松实现OSGi动态-掌握OSGi动态的Scala DSL

    domino:轻松实现OSGi动态-掌握OSGi动态的Scala DSL

    一种基于OSGi的动态演化方法

    一种基于OSGi的动态演化方法一种基于OSGi的动态演化方法

    深入理解OSGi

    深入理解Java虚拟机作者周志明又一力作,深入理解OSGi Equinox原理、应用与最佳实践 PDF 完整版

    深入理解osgi

    深入理解osgi,本书由浅入深的讲解了osgi的发展历程,模块层规范,生命周期层规范,以及基本实现原理,对初学者和从业人员都有不错的指导意义

Global site tag (gtag.js) - Google Analytics