OSGi/Equinox 类加载器使用了意外的捆绑版本

Posted

技术标签:

【中文标题】OSGi/Equinox 类加载器使用了意外的捆绑版本【英文标题】:OSGi/Equinox Classloader uses unexpected Bundle Version 【发布时间】:2012-09-10 14:36:05 【问题描述】:

我有一个带有捆绑包的 OSGI 应用程序,需要 2 个版本的 IBM MQSeries: 6.0.2 和 7.0.1。 我们安装了以下 IBM MQ Bundle(仅提及主要的)

com.ibm.mq.osgi.client_6.0.2.5.jar com.ibm.msg.client.osgi.wmq_7.0.1.5.jar

我们将 2 个 Bundle 定义为 Require-Bundle 如下(是的,我知道,我们应该使用 import-package ;-)) 捆绑ARequire-Bundle: com.ibm.msg.client.osgi.wmq;bundle-version="7.0.1"

捆绑 B Require-Bundle: com.ibm.mq.osgi.client;bundle-version="[6.0.2,7.0.0)"

我们另外定义org.osgi.framework.bootdelegation=javax.*。 没有伙伴类加载,没有动态类加载。

现在,当 Bundle A 加载 com.ibm.mq.jms.MQQueueConnectionFactory 使用

final MQQueueConnectionFactory connectionFactory = new MQQueueConnectionFactory();

我希望 Equinox 从 Bundle com.ibm.msg.client.osgi.wmq_7.0.1.5 加载类。 不是这种情况 !?!?? MQQueueConnectionFactory 是从 Bundle com.ibm.mq.osgi.client_6.0.2.5 加载的!!

因此,Bundle A 使用的是 MQ 6.0.2.5..

设置一些 Equinox Debug 选项,我可以看到以下内容:

Bundle id 56 == com.ibm.mq.osgi.client_6.0.2.5
Bundle id 53 == com.ibm.msg.client.osgi.jms.prereq_7.0.1.5

[...]
BundleLoader[A_1.1.3].loadBundleClass(com.ibm.mq.jms.MQQueueConnectionFactory)
BundleLoader[com.ibm.mq.osgi.client_6.0.2.5].findLocalClass(com.ibm.mq.jms.MQQueueConnectionFactory)
BundleClassLoader[PATH/org.eclipse.osgi/bundles/56/1/.cp/com.ibm.mq.jar].findClassImpl(com.ibm.mq.jms.MQQueueConnectionFactory)
BundleClassLoader[PATH/org.eclipse.osgi/bundles/56/1/.cp/com.ibm.mqjms.jar].findClassImpl(com.ibm.mq.jms.MQQueueConnectionFactory)
  about to read 11659 bytes from com/ibm/mq/jms/MQQueueConnectionFactory.class
  read 11659 bytes from PATH/org.eclipse.osgi/bundles/56/1/.cp/com.ibm.mqjms.jar/com/ibm/mq/jms/MQQueueConnectionFactory.class
  defining class com.ibm.mq.jms.MQQueueConnectionFactory
[...]

“有趣”的部分是 javax.jms.* 类是从 com.ibm.msg.client.osgi.jms.prereq_7.0.1.5 加载的

BundleClassLoader[com.ibm.mq.osgi.client_6.0.2.5].loadClass(javax.jms.QueueConnectionFactory)
BundleLoader[com.ibm.mq.osgi.client_6.0.2.5].loadBundleClass(javax.jms.QueueConnectionFactory)
BundleLoader[com.ibm.msg.client.osgi.jms.prereq_7.0.1.5].findLocalClass(javax.jms.QueueConnectionFactory)
BundleClassLoader[PATH/org.eclipse.osgi/bundles/53/1/.cp/jms.jar].findClassImpl(javax.jms.QueueConnectionFactory)
  about to read 371 bytes from javax/jms/QueueConnectionFactory.class
  read 371 bytes from /opt/fxportal/FXMB/application/configuration/org.eclipse.osgi/bundles/53/1/.cp/jms.jar/javax/jms/QueueConnectionFactory.class
  defining class javax.jms.QueueConnectionFactory
BundleLoader[com.ibm.msg.client.osgi.jms.prereq_7.0.1.5] found local class javax.jms.QueueConnectionFactory

恕我直言,这与 org.osgi.framework.bootdelegation 设置以及 7.0.1.5 JMS prereq 发生在 6.0.2.5 之前的事实有关。

有人可以解释捆绑类加载器的行为吗?为什么 Equinox 以这种方式连接束 A?我怎样才能达到预期的行为?

Bundle B 正在按预期工作...

【问题讨论】:

【参考方案1】:

当我在 IDE 中使用 OSGi 相关编码时,我遇到了类似的情况。由您的 IDE 完成的这种接线是错误的。它从 com.ibm.mq.osgi.client_6.0.2.5 连接类,而您希望它连接同一类 com.ibm.msg.client.osgi.wmq_7.0.1.5 。在您谈到的第二个问题中,同样的问题正在发生。您可以通过查找 IDE 使用它的 com.ibm.mq.jms.MQQueueConnectionFactory 类来检查这一点。 (您可以使用 Ctrl + 鼠标单击查看已连接的版本)。

【讨论】:

【参考方案2】:

如果这是一个有效的答案,请不要尝试在 BUndle A version="[7.0.1,7.0.1]" 中定义依赖项时使用此格式,这表示严格的版本范围。更糟糕的情况是,如果您仍然遇到问题,您可以通过执行 Platform.getBundle("com.ibm.msg.client.osgi.wmq").loadClass("com.myclass") 直接从 Bundle 加载类?

【讨论】:

以上是关于OSGi/Equinox 类加载器使用了意外的捆绑版本的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式启动 OSGi(Equinox)?

OSGi:以编程方式决定是不是可以启动捆绑包

Persistence.xml 和 OSGi (Equinox)

如何在 Equinox 中获取捆绑包的类加载器?

Eclipse 中的 OSGi 无法解析依赖关系

OSGi 中的 Java 类加载器使用