【问题标题】:Package uses conflict: Import-Package on startup of a bundle包使用冲突:包启动时的 Import-Package
【发布时间】:2011-07-27 02:56:24
【问题描述】:

我在尝试安装 htmlunit 包时收到以下错误:

com.springsource.com.gargoylesoftware.htmlunit_2.6.0 [370] could not be resolved.
  Reason: Package uses conflict: 
  Import-Package: org.apache.commons.logging.impl; version="1.1.1"

我已按照this blog 上此类问题的诊断程序进行操作。

以下是我的发现: 捆绑包com.springsource.com.gargoylesoftware.htmlunit_2.6.0 具有以下说明:

Import-Package: \
  org.apache.commons.logging;version="[1.1.1, 2.0.0)",\
  org.apache.commons.logging.impl;version="[1.1.1, 2.0.0)"

在我的 OSGi 中,唯一具有此使用约束的捆绑包是 com.springsource.org.apache.commons.logging,其中包含以下说明:

Export-Package: \
  org.apache.commons.logging;version="1.1.1",\
  org.apache.commons.logging.impl;version="1.1.1";\
    uses:="javax.servlet,
           org.apache.avalon.framework.logger,
           org.apache.commons.logging,
           org.apache.log,
           org.apache.log4j"

Import-Package: \
  javax.servlet;version="[2.1.0, 3.0.0)";resolution:=optional,\
  org.apache.avalon.framework.logger;version="[4.1.3, 4.1.3]";resolution:=optional,\
  org.apache.log;version="[1.0.1, 1.0.1]";resolution:=optional,\
  org.apache.log4j;version="[1.2.15, 2.0.0)";resolution:=optional   

此时我被卡住了,因为我无法弄清楚问题是什么以及如何解决它,尽管从我上面提供的内容来看应该很清楚,但对我来说不是:(

有什么想法吗...?

【问题讨论】:

    标签: osgi


    【解决方案1】:

    这很可能与“import-what-you-export”有关。

    uses 约束声明“如果你想导入这个包,最好确保你使用的是与我相同的包”,这不仅意味着包的版本,而且 相同 包,由同一个包导出。 您的第二个捆绑包导出了logginglogging.impl 包,说明“如果您想使用logging.impl,请使用与我相同的logging”,它也恰好导出了一个。这意味着任何想要导入logging.impl 必须的人也从你的包中导入logging,因为它不能连接到任何其他logging 包。 如果框架中有另一个 logging 副本,这会导致问题,这可能会更早得到解决。

    解决此问题的最简单方法可能是将logging 添加到第二个捆绑包的Import-Package。这样,您就可以将使用哪个包的具体选择权留给框架。

    在一个无关的注释中,去掉所有那些";resolution:=optional 语句,除非你的代码真的可以在某些包不可用的情况下工作。如果没有javax.servlet 可用,您的捆绑包可以正常工作,我会感到非常惊讶。

    【讨论】:

    • 您好 Angelo,非常感谢您提供清晰详细的回答!首先,在第二个包的 Import-Package decleration 中添加 org.apache.commons.logging(不说明版本)已经解决了这个特定问题,但我想确保我理解更改的含义:这意味着现在osgi 框架现在控制要使用的日志记录,而不是我。对吗?
    • 我猜我在问是否有办法以不同的方式解决这个冲突......?
    • 框架不控制使用哪个日志,它只控制logging包的接线。此外,您可能应该将;version="[1.1.1, 2.0.0)" 添加到导入中,以确保您不会连接到不兼容的不同软件包版本。
    • 至于“有没有其他方法可以解决这个问题”,恐怕真的没有。 OSGi 上下文中的打包是一个微妙的主题,您应该认真考虑一下。模块化很难,OSGi 只是让你更明确。您可能应该考虑还有谁会输出这个,为什么,以及您想要达到什么目标。对此没有一刀切的建议。
    • 再次感谢安吉洛。阅读了您的上一个回复后,我不确定 100% 是否了解解决方案...我们在第二个包中添加了 Import-Package 的日志记录减速,这意味着该包现在希望获得第三个包的日志记录。这第二个捆绑包是日志本身的来源,所以我想知道它现在从哪里得到它......?
    【解决方案2】:

    检测 (Eclipse) OSGI 错误“使用冲突” 解决有冲突的大型捆绑树是一项乏味的工作。 最容易解决的错误是“缺少约束”。这只是缺少包或类,错误明确说明缺少哪个 java 包/包。 我要关注的是神秘的 OSGI 错误消息,称为“uses-conflict”。 Equinox OSGI 工具没有提供太多关于造成版本冲突的包名的信息。那里有很多论文解释了如何解决冲突,但是,没有一篇显示如何快速找到发生冲突的包。 这是一种确定哪个包+版本导致冲突的方法。 我们将从一些虚构的项目开始:一个开发人员编写了一个 Eclipse 插件 + 几个包 (JAR)。 该插件主要包含 UI 代码,而 JAR 主要包含共享/可重用逻辑。 开发人员将它们全部打包到一个 Eclipse 功能中并尝试安装它。 由于“使用冲突”,插件无法启动。

    你有一个插件。您安装但由于“使用冲突”而无法启动 关闭日食。 通过命令行(linux)重新运行eclipse:

       ./eclipse -console -consoleLog -data /tmp/eclipseTest/workspace/ -clean 
    

    (win32 用户当然应该调用 eclipse.exe) 该命令将打开我们稍后需要的 osgi 控制台。 当 eclipse 加载完成后,切换回 eclipse 命令行窗口。您应该会看到“osgi>”命令提示符(如果没有按两次 Enter) 找到你的 plugin/bundles 的 Java 包。假设它被命名为 com.A , B, C , D 和 E 在 osgi 控制台中运行:

        osgi> ss com.A
    
        id    State       Bundle
        7    INSTALLED  com.A
        osgi> start 7
    

    org.osgi.framework.BundleException:无法解析捆绑包“com.A [7]”。原因:包使用冲突:Require-Bundle: com.B;捆绑版本="0.0.0" 在 org.eclipse.osgi.framework.internal.core.AbstractBundle.getResolverError... 更多堆栈在这里...

    现在我们知道 com.A 依赖于 bundle com.B 的 bundle 和 com.B 有冲突。原因当然是营养用途冲突。 (旁注:实际的冲突可能会被进一步隐藏:在 com.B 所依赖的其他捆绑包中,但现在让我们忽略这一点) 我们希望达到的理想状态是:

       osgi> ss com.A
       Framework is launched.
       id    State       Bundle
       7    ACTIVE      com.A
    

    但我们还没有。

    所以我们知道 bundle com.B 是有问题的。 我们可以通过运行查看它尝试加载(但失败)的导入列表

       osgi> bundle 10   
    

    (10 是我们的 com.B 包从 OSGI 容器中获取的随机包 ID。只需在 osgi 控制台中运行:“ss com.B”即可找到它的包 ID)

    • 关注“导入包”部分。把它复制到某个地方。 在将插件安装到 Eclipse 框架时,它实际上被解压缩到 Eclipse 的插件目录中。打开文件资源管理器并转到 /plugins 。找到“坏”包的目录(解决“使用冲突”的那个)它可能会被命名为 com.B.[version_or_timestamp]。

    • 深入到 META-INF 目录。编辑 manifest.mf:首先清理 Import-packages 部分(将该部分剪切粘贴到记事本)

    • 重启eclipse(Ctrl+C退出osgi控制台中运行的eclipse然后重新运行) 现在 eclipse 应该说 bundle 是“活动的”。如果它没有在活动模式下启动,它可能会遇到 Missing-Constraint 错误。这很容易解决,因为错误信息量很大,但这不是这里的重点。

    • 直到 uses-conflict re-pop:开始将该清单中的 Import-packages 部分重新填充到其原始状态。一次只做一个 java 包,这样您就可以查明导致“使用冲突”的更改

    • 在记事本中编辑 manifest.mf 时,请确保在第 71 列按 Enter,并且下一行以单个空格开头。您可能已经注意到,清单具有您必须遵循的独特的换行结构。

    • 重启 Eclipse(在 osgi 控制台中按 Ctrl+C 然后重新运行)。

    • 通过运行 osgi 命令“ss com.A”重新测试捆绑包状态,尝试“start com.A”并查看是否出现任何错误。

    • 在每次 manifest.mf 更改后重新启动 eclipse。

    将错误的 java 导入添加到 manifest.mf 后,您将看到捆绑包仅标记为“已解决”(而不是活动的)。 让我们假设您发现的第一个破坏捆绑包的 java 包是 javax.xml.bind。 在 OSGI 控制台运行:“packages javax.xml.bind”,您应该会看到该命名空间的已解析 OSGI 捆绑包+版本+使用的列表。如果您有多个提供程序(即多个版本 - 它是一棵树。查看它的根),您可能需要更改原始包并强制它导入特定版本(通过使用 Import 中的“version”指令-Package 部分。例如 javax.xml.bind;version="[2.1,3)" 这是告诉 osgi 搜索范围) 通常,如果您编写 OSGI 包或 Eclipse 插件,最佳实践是尽可能在 Import-package 标头中明确指定 Import 版本范围(并且不要使用默认值,即 0.0.0 或任何版本)。同样的规则也适用于有时在 Import-Package 标头中使用的 uses:= 指令。

    同样适用于 Require-Bundle 标头:最好使用“bundle-version”OSGI 指令来确保您获得所需的版本。 如果在构建过程中使用 Maven,它就更重要了,因为它允许 maven 正确计算版本依赖关系(尤其是在使用 Felix maven-bundle-plugin 时)

    另一个问题是有时你确实需要在你的 bundle 清单中: 导入包:javax.xml.bind;version=”[2.1.9,3)” 但由于某种原因,这不能满足。如果可能的话,您可以将您的版本范围扩大到更广泛的版本。

    当您解决您的 OSGI 冲突时,不要忘记相应地编辑您的原始构建清单/脚本。

    旁注:您也可以尝试运行“eclipse.exe -clean”,它可能会正确地重新计算捆绑包依赖项并让您的插件启动,但这不是一个长期的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-28
      • 2017-09-26
      • 2019-03-07
      • 2016-01-28
      • 1970-01-01
      • 2016-02-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多