【OSGi】Require-Bundle与Import-Package

Require-Bundle的作用

Another kind of constraint that can be placed on a bundle is the Require-Bundle header. This is similar to Import-Package header in that it makes exported packages from another bundle available to our bundle, but it works on the whole bundle rather than individual packages.

Bundle B has a Require-Bundle dependency on Bundle A, meaning that Bundle B cannot resolve unless Bundle A is in RESOLVED state. The effect at runtime is as if Bundle B had declared an Import-Package header naming every package exported by Bundle A.

However, Bundle B is giving up a lot of control, because the list of imports is determined by the set of packages exported by Bundle A. If additional exports are added to Bundle A, then they are automatically added as imports to Bundle B.

    

Require-Bundle和Import-Package功能类似,都是使得其他bundle的导出包对我们的bundle可用。但是Require-Bundle是作用在整个bundle上的;Import-Package是作用在单个包上。

假设bundleB require bundleA,则相当于bundleB中import了bundleA的所有包。但是import了哪些包是由bundleA决定的,bundleB控制不了。

Require-Bundle的缺点

The use of Require-Bundle is strongly discouraged by most OSGi practitioners except where absolutely necessary, because there are several flaws with this kind of dependency scheme.

1、不知道究竟导入了哪些包

First, a bundle using Require-Bundle to import code from another bundle is at the mercy of what is provided by that bundle — something that can change over time. We really have no idea what packages will be provided by another bundle at any point in the future, yet nevertheless our bundle will successfully resolve even if the required bundle stops exporting some functionality that we rely on. The result will almost certainly be class loading errors such as ClassNotFoundException or NoClassDefFoundError arising in bundles that were previously working.

我们不知道究竟导入了哪些包,在不同版本中导入的包可能不同;

即便bundleA不再导出我们需要的某些包,bundleB仍然能正常解析,但是在运行时会抛出ClassNotFoundException或NoClassDefFoundError。

2、导出包的bundle重构后,会影响导入bundle

The second and closely related problem is that requiring bundles limits our ability to refactor the composition of those bundles. Suppose at some point we notice that Bundle A has grown too big, and some of the functionality it provides is really unrelated to the core and should be separated into a new bundle, which we will call Bundle A‘. As a result, some of the exports of A move into A’.

For any consumers of that functionality who are using purely Import-Package, the refactoring of A into A and A‘ will be entirely transparent: the imports will simply be wired differently at runtime by the framework. Figures 3.3 and 3.4 show the “before” and “after” states of performing this refactoring where Bundle B depends on the packages of BundleA using Import-Package. After refactoring, Bundle B will continue to work correctly because it will still import all the packages it needs – and it will be oblivious of the fact that they now come from two bundles rather than one.

如果bundleA日渐臃肿,打算将其分拆成两个bundle。如果使用Import-Package,则仍能正常工作:

  

However, Figures 3.5 and 3.6 show the “before” and “after” states when Bundle B requires Bundle A using Require-Bundle. After refactoring, Bundle B will no longer import one of the packages it needs, but it will still be able to enter the RESOLVED state because the Require-Bundle constraint is still satisfied. Therefore we are likely to get NoClassDefFoundErrors when B attempts to use classes from org.package2.

但是如果使用Require-Bundle,则新的bundle不会被bundleB导入;可能会抛出NoClassDefFoundErrors。

3、导致导入大量无用的包

Third, whole-module dependency systems tend to cause a high degree of “fanout”. When a bundle requires another bundle, we have no idea (except by lowlevel examination of the code) which part of the required bundle it is actually using. This can result in us bringing in a large amount of functionality when only a small amount is really required. The required bundle may also require several other bundles, and those bundles require yet more bundles, and so on. In this way we can easily be required to pull in fifty or more bundles just to resolve a single, small bundle. Using purely Import-Package gives us the opportunity to break this fan-out by finding instances where only a small portion of a large bundle is used, and either splitting that bundle or finding an alternative supplier for the functionality we need.

即便只依赖bundleA中的一小部分代码,也需要导入其中的所有包;而bundleA又会依赖其他bundle,最终导致导入了大量无用的包。

而用Import-Package则不会有这个问题。

为什么引入Require-Bundle?

Essentially, using Require-Bundle is like grabbing hold of the wrapper around what we need, rather than the contents itself. It might actually work if JARs in Java were more cohesive, and the constituent packages did not change over time, but that is not the case.

Require-Bundle was only recently introduced into OSGi in Release 4, and given all the problems listed, it may seem mysterious that it was introduced at all. The main reason was to support various legacy issues in Eclipse, which abandoned an earlier module system in favour of OSGi. The pre-OSGi module system used by Eclipse was based on whole-module dependencies, and if OSGi had offered only Import-Package then the challenges of making thousands of existing Eclipse plug-ins work as OSGi bundles would have been insurmountable. Nevertheless, the existence of Require-Bundle remains highly controversial, and there are very, very few good reasons ever to use it in new bundles.

引入Require-Bundle主要是因为Eclipse的历史遗留问题。在使用OSGi之前,Eclipse是基于全模块依赖的,如果OSGi仅仅支持Import-Package,要想让成千上万已有的Eclipse插件正常工作,几乎是不可能的。

猜你喜欢

转载自blog.csdn.net/vking_wang/article/details/13240715