如何在OSGi中添加特定包版本的import-packages

时间:2014-11-11 18:36:30

标签: java osgi cq5 aem sling

我的项目有两个OSGi包(A和B)需要使用不同版本的javax.activation - A需要1.1.0版本,而B需要1.1.1。

默认情况下,在AEM 5.6.1中,已经安装了一个捆绑包,用于导出捆绑A正在使用的版本1.1.1。为了使它使用1.1.0 instaed,我使用了boot委托从JRE 7获取了1.1.0的系统包的javax.activation。我使用AEM 5.6.1中的sling.properties文件设置它。

如果我在此sling.properties文件中为javax.activation提供大于1.1.1的版本,则A和B都使用系统版本(即使manifest.mf中指定了import-packages的版本文件);但如果我给的版本低于1.1.1,则两个捆绑包都使用AEM提供的版本。

如何配置我的软件包以便为Bundle B中的Bundle A使用不同版本的javax.activation?

2 个答案:

答案 0 :(得分:2)

如果你想在套装A中使用完全1.1.0版本,那么你应该在A的清单文件中指定它:

Import-Package: javax.activation;version="[1.1.0,1.1.0]"

对于捆绑包B清单将是:

Import-Package: javax.activation;version="[1.1.1,1.1.1]"

答案 1 :(得分:1)

由于OSGI捆绑解析规则,这可能非常困难。看看这篇文章 - 我发现这是对适用的各种规则的一个很好的解释。具体来说,请查看uses指令: http://www.christianposta.com/blog/?p=241

如果有两种方法可以使用相同的版本(但我知道这可能并不总是可行),生活将变得更加简单。

这来自上面的文章:

  

对于每个Import-Package包声明,必须有一个   具有相同包的相应Export-Package

     

Bundles还可以将其他属性附加到它导入的包或   出口。如果我们在示例中添加了一个版本属性,该怎么办:

     

Bundle-Name:Bundle A Import-Package:org.apache.foo; version =" 1.2.0"

     

这意味着,Bundle A依赖于org.apache.foo包   最低版本1.2.0。是的,你读得正确。虽然有OSGI   如果没有指定范围,则可以指定一系列版本   而是使用固定版本,它将导致“最小”的含义   固定价值。如果有相同的更高版本   包,将使用更高版本。所以捆绑A将无法解决   除非有相应的B组导出,否则正确   必需的包裹:

     

Bundle-Name:Bundle B Export-Package:org.apache.foo; version =" 1.2.0"

     

请注意反之亦然......如果Bundle B导出版本1.2.0,   Bundle A不需要指定版本1.2.0。它可以使用它   导入并解决得很好:

     

Bundle-Name:Bundle A Import-Package:org.apache.foo

     

这是因为导入声明了他们需要的版本。出口了   version没有指定导入包必须使用的任何内容(哪个   适用于任何属性,而不仅仅是版本)。 Import-Package指令   确切地说它需要什么版本(或属性),以及相应的   必须存在具有相同属性的Export-Package

     

如果您有Bundle A导入包的场景会发生什么   它指定了由两个包提供的版本:

     

Bundle-Name:Bundle A Import-Package:org.apache.foo; version =" 1.2.0"

     

Bundle-Name:Bundle B Export-Package:org.apache.foo; version =" 1.2.0"

     

Bundle-Name:Bundle C Export-Package:org.apache.foo; version =" 1.2.0"

     

Bundle A使用哪一个捆绑包?答案取决于哪个   首先安装捆绑(B或C)。首先使用安装的捆绑包   在具有相同版本的多个包时满足依赖性   找到了

     

热部署捆绑包时,事情会变得复杂一些   一些已经解决后。如果安装Bundle B怎么办?   首先,然后尝试安装Bundle A和以下Bundle D.   一起:

     

Bundle-Name:Bundle D Export-Package:org.apache.foo; version =" 1.3.0"

     

正如我们从上面看到的,Bundle A中的版本声明(1.2.0)   表示最低版本1.2.0;所以如果有更高版本可用   然后它会选择(在这种情况下来自Bundle D的版本1.3.0)。   然而,这带来了另一个捆绑的时间规则   解决方案:已经解决的捆绑包具有更高的分辨率   那些未解决的优先级

     

原因是OSGI框架倾向于支持可重用性   对于给定的捆绑。如果它已经解决,而新的捆绑包需要它,那么它   如果它不会尝试拥有相同包的许多其他版本   不需要。捆绑“使用”指令

     

上述捆绑解析规则仍然不够而且   错误的类仍然可以在运行时使用,从而导致类转换   例外或类似。你能看到可能遗漏的东西吗?

     

如果我们有这种情况怎么办? Bundle A导出包,   org.apache.foo,包含一个类FooClass。 FooClass有一个方法   返回BarClass类型的对象,但未定义BarClass   在bundle的类空间中,它是这样导入的:

     

1 2 3公共课FooClass {       public BarClass execute(){...}}

     

Bundle-Name:Bundle A Import-Package:org.apache.bar; version =" 3.6.0"   Export-Package:org.apache.foo; version =" 1.2.0"

     

到目前为止,只要有另一个捆绑包,一切都很好   正确导出org.apache.bar并使用正确的版本。

     

Bundle-Name:Bundle B Export-Package:org.apache.bar; version =" 3.6.0"

     

这两个捆绑包可以很好地解决。现在,如果我们再安装两个   bundle,Bundle C和Bundle D看起来像这样:

     

Bundle-Name:Bundle C Import-Package:org.apache.foo; version =" 1.2.0",   org.apache.bar;版本=" 4.0.0"

     

Bundle-Name:Bundle D Export-Package:org.apache.bar; version =" 4.0.0"

     

我们可以看到Bundle C从Bundle导入了一个包org.apache.foo   A. Bundle C可以尝试使用org.apache.foo中的FooClass,但是当它   得到返回值,一种BarClass,会发生什么?捆绑A.   期望使用版本3.6.0的BarClass,但是捆绑C正在使用   版本4.0.0。所以使用的类在bundle中是不一致的   在运行时(即,您可能会遇到某种类型的不匹配或类   抛出异常),但在部署时一切仍然可以解决   时间遵循上述规则。我们需要的是告诉任何人   导入我们使用特定类的org.apache.foo   org.apache.bar的版本,如果你想使用org.apache.foo你   必须使用我们导入的相同版本。这正是它的用途   指令呢。让我们更改捆绑包A以准确指定:

     

Bundle-Name:Bundle A Import-Package:org.apache.bar; version =" 3.6.0"   Export-Package:org.apache.foo; version =" 1.2.0"&#34 ;; uses:= org.apache.bar

     

鉴于Bundle A的新配置,捆绑包不会   从上面正确解决。捆绑C无法解决,因为它   导入org.apache.foo,但Bundle A上的“uses”约束指定   C必须使用与A(3.6.0)相同的版本   org.apache.bar,否则捆绑在尝试时将无法解析   部署。对此的解决方案是更改Bundle C中的版本   org.apache.bar为3.6.0。