bundle动态更新

  实际项目开发中,更新Bundle时遇到这样一个问题(基于Knopflerfish框架的OSGi):

     项目大概框架为主Bundle(暂时称之为MainBundle)调用其他Bundle(SubBundles)提供的方法来进行相应的数据运算,现在想更换某个Bundle(SubBundle1)的算法,用新生成的Bundle覆盖掉老的版本,update该SubBundle之后,发现MainBundle调用其方法后得出的仍然是老版本的结果。直接将SubBundle1 Uninstall,再重新Install,start后,运算结果依然没变。更奇怪的是把SubBundle1 Uninstall之后,MainBundle调用的结果和SubBundle1 Uninstall之前完全一样,初步猜测是还有一个SubBundle1副本之类的东西保存在OSGi中。

几番尝试之后发现以下两种方式可以实现真正的更新:

1:重新安装SubBundle1之后,再将MainBundle也重新安装运行能得出新版SubBundle1的运算结果。

2:SubBundle1执行Update操作之后,再执行Refresh操作(此过程中输出信息显示:调用了SubBundle1的MainBundle会自动执行停止和开始操作)。

     看来Bundle的Update过程还有点玄机。

     原来,对于没有对外暴露Package的Bundle,可以正常完成Update过程,一般的,这些没有对外暴露Package的Bundle暴露的都是OSGi服务,在Update过程中会把依赖了此OSGi服务的OSGi组件的实例销毁,新版本的Bundle更新启动之后,会重新实例化该OSGi组件。

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

以上过程可以简单用下图表示:

bundle动态更新_第1张图片


总结:在OSGi中如果要更新没有对外提供package的Bundle是比较容易的,update或者uninstall-->start都可以实现,而对于对外提供了package的Bundle而言,则稍有不同,不管之前是update还是install,最后必须再执行refresh操作来完成真正的更新。



你可能感兴趣的:(bundle动态更新)