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.



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


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.


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.




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.



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.





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.




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.






©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客