OSGi 捆绑包更新如何工作?
当更新某个捆绑包(例如修复错误)时,当前正在使用正在更新的捆绑包的其他捆绑包会发生什么情况?
假设有两个bundle service 和dao。当我发出更新 dao 层的命令时,假设服务包中的类正在使用 dao 包中的类。 service层的类使用dao代码会出现异常吗?
感谢您的回复。
我的意思是说更新了相同的版本。
直到发生包含依赖包的包刷新。
捆绑包刷新操作是由更新捆绑包的用户调用的,对吗?假设当用户调用刷新来更新 dao 包时,bundle 服务中的类调用了 dao 层中类的方法......在这种情况下会发生什么?
我发现这篇博文很有帮助: http:// Solutionsfit.com/blog/2008/08/27/osgi-what-modularity-can-do-for-you-part-1/
来自帖子:
如果我们只是用包含修复程序的包替换该包,容器将取消注册旧包并注册新包。然后,代理可以处理引用改组并恢复服务调用。这种互动几乎是瞬时的。您的客户将完全忘记发生的事情,而您刚刚为您的公司节省了一大笔钱(我听到奖金了吗?)。
在这篇博文中,对authorizePayment()的调用被搁置,直到更新的捆绑包可用为止。当捆绑刷新发生时,如果控件位于 AuthorizePayment() 方法内,会发生什么情况?
When a bundle is updated (say to fix a bug), what happens to other bundles that are currently using the one being updated?
Say that there are two bundles service and dao. Say that classes in service bundle are using classes in dao bundle when I issue command to update dao layer. Will the class in service layer using dao code get an exception?
Thanks for your response.
I meant to say updated with the same version.
until a bundle refresh occurs which includes the dependent bundle.
Bundle refresh operation is invoked by the user updating the bundle, right? Say that when user invokes refresh to update dao bundle, a class in bundle service invoked a method on a class in dao layer... what happens in this scenario?
I found this blog post helpful:
http://solutionsfit.com/blog/2008/08/27/osgi-what-modularity-can-do-for-you-part-1/
From the post:
If we simply replace the bundle with a bundle that includes the fix, the container will unregister the old bundle and register the new bundle. The proxy can then handle the reference shuffling and resume the service invocation. This interaction will be almost instantaneous. Your customers will be completely oblivious to what has happened and you just saved your company a substantial amount of money (do I hear bonus?).
In this blog post, the call to authorizePayment() was put on hold until the updated bundle is available. What happens if the control is within the authorizePayment() method when bundle refresh happens?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
捆绑包有两种依赖关系:
类加载器,由包作为键控
名称。这些连接称为
电线。
服务很容易撤回,因为这是其设计的本质。电线更硬,因为它们错综复杂地编织在你的物体中,而这些物体不知道动态。因此,当您安装新捆绑包时,旧捆绑包将保持原样,您的对象不会更新,并且更新后的捆绑包仍将其电线作为僵尸提供。
当您调用refreshPackages时,框架会查看这些依赖项并找到引用这些僵尸的包。然后每个僵尸都被停下来。捆绑包的约定是它应该进行清理。我们通过为您进行大量清理来帮助该捆绑包,但有些事情非常糟糕,例如将引用存储在其他捆绑包的静态中或忘记停止已启动的线程。以其他方式依赖于这些捆绑包的其他捆绑包会收到捆绑包停止的通知,以便它们也可以清理任何引用。捆绑包停止后,捆绑包将无法解析,然后针对新捆绑包再次解析。
对于真正的 OSGi 包,清理是自然的,并且在代码中并不真正可见(本来应该如此)。它得到声明式服务、iPOJO、依赖管理器、Spring、Blueprint 等工具的良好支持。神奇之处在于 µservices 模型,而不是 dong 类加载技巧。
为什么我们不自动刷新?嗯,我们曾经这样做过,但刷新会造成破坏。在许多情况下,您需要更新多个捆绑包。每次更新后都会出现这种中断,这将是不必要的痛苦。也就是说,在安装或更新后,您应该始终进行刷新,但您可以将多个安装/更新括起来。
Bundles have 2 kind of dependencies:
class loaders, keyed by the package
names. Those connections are called
wires.
Services are easy to withdraw because that is intrinsic to their design. Wires are harder because they are intricately woven in your objects and those objects are not aware of the dynamics. So when you install a new bundle, the old bundles stay as they are, your objects are not updated and the updated bundle still provides its wires as a zombie.
When you call refreshPackages the framework looks at those dependencies and finds the bundles that refer to those zombies. Every zombie is then stopped. The contract for a bundle is that it should cleanup. We help the bundle by doing a lot of cleanup for you, but some things are very bad, e.g. storing references in statics of other bundles or forgetting to stop threads that were started. Other bundles that depend in other ways on those bundles get notified of the bundle stopping so they can also clean up any references. After the bundles are stopped, the bundles are unresolved and then resolved again against the new bundles.
For real OSGi bundles the cleaning up is natural and not really visible in your code (as it should be). It is well supported by the tools like Declarative services, iPOJO, dependency manager, Spring, Blueprint, etc. The magic is focus on the µservices model and not dong class loading hacks.
Why are we not refreshing automatically? Well, we once did but refreshing is disruptive. In many cases you need to update multiple bundles. Having this disruption after each update would be unnecessary painful. That is, after an install or update you should ALWAYS do a refresh but you can bracket a number of installs/updates.
当您使用 OSGi 'update' 命令更新捆绑包时,很可能有其他依赖它的捆绑包并且已经捕获了一组加载的类来自此捆绑包的旧版本。通常符合您在问题中描述的问题的情况。
为了避免该包所包含的不同版本的类之间可能出现不一致,OSGi 容器决定暂时对外界隐藏更新后的包的类的新版本。您可以将其视为暂时将更新的类与其他包隔离。。
这里的要点是,OSGi 容器不能只是开始从目标包的新版本加载类,因为依赖包最终会看到它们已加载的类的旧版本,与它们所加载的相同类的新版本混合在一起。更新后加载,这会导致不一致,从而导致无法控制的混乱。捆绑包卸载也是如此,该捆绑包将从已安装的捆绑包列表中删除,但不会从内存中删除。应保留它,以便依赖包可以继续从中加载类。
因此,您可以将“更新”命令视为引入同一捆绑包的新版本,仅提供给尚未发布的依赖捆绑包 - 当时尚未存在更新的-.虽然旧版本(更新前已存在)仍保留在内存中,以确保向后兼容性并避免对已开始依赖于更新包的现有包造成任何可能的干扰。
请注意,旧版本仅保留在内存中,这意味着重新启动服务器将导致消除所有这些旧版本并将最新版本带入表中。这是完全有道理的,因为不需要向后兼容,只是因为所有捆绑包现在都同时启动..
接下来发生的事情是,您必须显式调用 '刷新'特定捆绑包的命令,-那些取决于更新的捆绑包-,或者您可以选择运行“刷新”命令而不指定特定的捆绑包,这意味着所有捆绑包都将一味地刷新。 “刷新”命令强制重建目标包的依赖关系树,并强制其类加载器从头开始加载所需的类。
只有这样,依赖包才会开始看到您对已更新的包中的类的代码所做的更改。
规则是:
When you update a bundle, using the OSGi 'update' command, it is most likely to have other dependent bundles that are relying on it and already capturing a set of loaded classes from the old version of this bundle. A situation that typically conforms to the problem you described in your question.
In order to avoid possible inconsistency between the different versions of the classes enfolded by this bundle, the OSGi container decides to temporarily hide the new version of the updated bundle's classes from the outside world. You can think of it as kind of keeping the updated classes in isolation from the other bundles -momentarily-.
The point here is that the OSGi container can’t just start loading classes from the new version of the target bundle, because the dependent bundles would end up seeing old versions of the classes they already loaded, mixed with new versions of the same classes that were loaded after the update, which would incorporate an inconsistency that would result in an uncontrollable mess. The same goes for the bundle Uninstall, the bundle is removed from the installed list of bundles, but it is not removed from memory. It shall be kept around so that dependent bundles can continue to load classes from it.
So you can think of the 'update' command, as introducing a new version of the same bundle, to be only supplied to dependent bundles that are yet to come, -which are not yet there at the time of the update-. While the old version -that existed before the update-, remains in memory in order to assure backward compatibility and avoid any possible disruption to existing bundles that have already started to depend on the updated bundle.
Note, that the old versions are only kept in memory, which means that a restart to the server will result in eradicating all these old versions and bring the latest version to the table. This makes perfect sense, because there will be no need for backward compatibility, simply because all bundles are now starting at the same time..
What happens next, is that you have to explicitly invoke the 'refresh' command on specific bundles, -those which are depending on the updated bundle-, or instead you can choose to run the 'refresh' command without specifying a specific bundle, meaning that all bundles will be blindly refreshed. The 'refresh' command forces the rebuilding of the dependency tree of the target bundles, and coerce their class loaders to start loading their required classes from scratch.
Only then dependent bundles will start to see the changes you have made to the code of the classes living in the bundle that has been updated.
The rule is that
更新捆绑包时,会安装新的修订版(捆绑包的各个部分)。如果另一个bundle连接到更新的bundle的先前版本,也就是说,另一个bundle导入了先前版本导出的某些包,或者另一个bundle需要先前版本的bundle,那么OSGi框架将保留更新的bundle的先前版本包以服务来自依赖包的未来类加载请求,直到发生包含依赖包的包刷新。
这样做的目的是在更新依赖项时最小化或延迟对依赖包的干扰。管理代理可能想要更新多个捆绑包,并在最后进行捆绑包刷新以“现代化”依赖项。捆绑包刷新完成后,就不会再连接到更新后的捆绑包的先前版本,并且 OSGi 框架现在可以随意丢弃先前的修订版。
所以在你的例子中,通常不会产生异常。但当然,这取决于相关代码实际上在做什么以及它们的捆绑清单是如何编写的。
When a bundle is updated, a new revision (the bits of the bundle) is installed. If another bundle is wired to the prior revision of the updated bundle, that is, another bundle imported some package exported by the prior revision or another bundle required the bundle at the prior revision, then the OSGi framework will retain the prior revision of the updated bundle to service future class load requests from the dependent bundle until a bundle refresh occurs which includes the dependent bundle.
The purpose of this is to minimize or delay perturbing dependent bundles when a dependency is updated. A management agent may want to update several bundles and, at the end, do a bundle refresh to "modernize" the dependencies. Once the bundle refresh is done, there are no wires to the prior revision of the updated bundle and the OSGi framework is now free to discard the prior revision.
So in your example, generally no exception will result. But of course it depends upon what the code in question is actually doing and how their bundle manifests are written.