自动解析依赖
OSGi框架执行的最重要的任务之一就是自动化管理依赖,也就是bundle依赖解析。
bundle类加载器
在执行时,每个bundle都有一个与之关联的类加载器,这个类加载器使得bundle可以获得其有权访问的所有类。当导入bundle连接到导出bundle时,导入bundle的类加载器会得到导出bundle的类加载器引用。因此导入bundle可以委托导出bundle的类加载器,去请求导出包中的类。
多个匹配包的情况
OSGi框架的优势之一就是支持并行的多版本。如果导入bundle可以找到多个对应的导出bundle,OSGi如何确定使用哪个导出bundle呢?
例如:
//导入bundle Import-Package: javax.servlet; version="2.4.0" //导出bundle1 Export-Package: javax.servlet; version="2.4.0" //导出bundle2 Export-Package: javax.servlet; version="2.5.0"
如果两个导出bundle都已被解析;则OSGi会选择 版本号更高的选项!(导出bundle2)
如果两个导出bundle版本号相同;则OSGi会按照安装顺序来选择!
另外,OSGi框架允许在执行过程中动态地安装bundle;也就是说,可能导出bundle1已安装,但导出bundle2还未安装;此时OSGi框架会优先选择已安装的导出bundle,即便他并不是最高版本!
总之,OSGi选择bundle的优先级为:
- 首先选择已解析的候选bundle;当有多个匹配项时,再按照版本号、按照顺序来选择
- 其次选择未解析的候选bundle;当有多个匹配项时,再按照版本号、按照顺序来选择
使用uses指令保证一致性
OSGi框架在进行bundle依赖解析时,每次都作出最有的选择。但是由于可以动态安装bundle,解析过程具有增量特性,OSGi框架无法作出全局最优的选择。
【例】
例如编写了一个HTTP服务bundle,import javax.servlet; version=2.4.0;将这个HTTP服务bundle、导出bundle1同时安装到OSGi,框架能正确地解析依赖;
Export-Package: org.alpha.service.http Import-Package: javax.servlet; version="2.4.0"
还有一个HTTP客户端bundle,依赖于HTTP服务:
Import-Package: org.alpha.service.http,javax.servlet; version="2.4.0"
然后再将HTTP客户端bundle、导出bundle2再安装到OSGi;由于HTTP客户端bundle也要import javax.servlet,OSGi框架会解析为导出bundle2!因为他的版本更高!
——这就导致了不一致性,HTTP服务、HTTP客户端所依赖的javax.servlet版本不一致!当服务bundle和客户端bundle交互时,会抛出异常!
【解决办法】
使用uses指定可以解决。uses指令对框架解析依赖关系时的选择进行了约束。
指令,是附加的元数据(类似属性),将框架解析元数据的方式改变为指令所申明的内容。
将HTTP服务bundle的元数据改为:
Export-Package: org.alpha.service.http; uses:="javax.servlet" Import-Package: javax.servlet; version="2.4.0"
上例中,导出包描述了与导入包之间的uses关系