【问题标题】:OSGi: how to ensure classpath consistency?OSGi:如何确保类路径的一致性?
【发布时间】:2011-11-20 11:18:22
【问题描述】:

根据 OSGi 文档,OSGi 旨在帮助防止 ClassPath 问题。

例如,来自“OSGi in action”:

在启动应用程序时出现 ClassNotFoundExceptions,因为 类路径不正确。 OSGi 可以通过确保代码提供帮助 在允许代码执行之前满足依赖关系。

但是,由于我们已将 java 应用程序切换到 OSGi,因此我看到的 ClassNotFoundExceptions 尤其是 NoClassDefFoundErrors 比以往任何时候都多。 OSGI 类加载器不再找到以前加载正常的类,更糟糕的是:您在运行时遇到错误,这意味着您无法轻松检查它,除非手动测试应用程序的每个角落。

例如,我们的应用程序在 OSGi 下运行良好,但我们收到来自 beta 测试人员的报告,他们无法再将文档导出为 PDF。确实,当我查看它时,我发现此功能导致记录异常:

java.lang.NoClassDefFoundError: org/w3c/dom/Node

那么,OSGi 是否真的创造了比它解决的更多的类路径问题?

更重要的是:我如何测试我的类路径与所有必要的 Import-Package 语句等是否一致。在我在错误报告中了解它们之前?

【问题讨论】:

  • “除了手动测试应用程序的每个角落” - erm 自动化测试? (这同样适用于任何应用程序)如果您在迁移之前有测试套件,那么您会在测试人员之前发现这些错误。要测试您的捆绑包是否正确连接,您需要进行一些集成测试 - 我们为此使用 Pax Exam 并进行简短的集成测试(当前捆绑包及其合作者)以及一些较长的端到端测试(测试整个应用程序)。
  • 对于那些在搜索 OSGi NoClassDefFound 时发现此堆栈溢出的人......请记住,执行 OSGi 包代码的当前 Java 线程决定了“活动”类加载器,即线程上下文类加载器 (TCCL)。 “活动”类加载器可能不是 OSGi 容器为捆绑代码创建的类加载器。所以为了让一切顺利,有时你必须手动切换线程的 TCCL。
  • 参见 2012 年。尼尔·巴特利特。 “可怕的线程上下文类加载器”,blogs.paremus.com/2012/10/….

标签: osgi noclassdeffounderror classnotfoundexception


【解决方案1】:

一个 OSGi 应用程序将不会抛出 ClassNotFoundExceptions 和 NoClassDefFoundErrors 如果你的清单是正确的。也就是说,你需要告诉 OSGi 你的包使用了哪些包;如果您没有正确或诚实地做到这一点,那么 OSGi 将无法帮助您。换句话说:GIGO(Garbage In,Garbage Out)。

例如,您使用包org.w3c.dom,但未在Import-Package 语句中列出它。因此 OSGi 不知道您需要访问该包,因此当您实际尝试从该包加载类时,它们不可用。

因此,您需要确保您的 Import-Package 声明对于您的捆绑包实际使用的软件包是准确的。好消息是“bnd”工具可以通过生成捆绑清单、使用字节码分析来查找所有静态引用的包来为您完成这项工作。

更新: 您的最后一个问题询问如何在运行时发现问题之前测试您的捆绑包是否一致。 Bnd 有一个“验证”功能可以做到这一点。实际上,如果您首先使用 Bnd 生成清单,那么您将不需要验证功能。但是,我对您的构建过程一无所知,因此您可能会发现很难在短期内迁移到基于 Bnd 的构建......在这种情况下,将验证任务添加为 post-构建后的处理步骤。但是我仍然建议在构建过程的早期尝试使用 Bnd。

【讨论】:

  • 我不知道bnd验证功能,很高兴知道!
  • "如果您的清单是正确的" .... 表示如果您的清单与您使用的特定实现完全一致,并且您没有做任何 OSGI 设计人员和编码人员您正在使用的特定实现没有考虑过。我同意 amarillion - OSGI 是类未发现问题的噩梦,几乎没有可用的故障排除机制。拥有更大的部署灵活性可能对最终用户很有价值,但对开发人员来说却是地狱。
  • @user252690 匿名胆小鬼很容易在互联网上发表侮辱性言论。如果你冷静下来并决定学习一些东西,你就会知道在哪里可以找到可以提供帮助的明智的人。
  • 请注意,如果您在 Source 选项卡中手动指定“Import-Package”语句(使用 bndtools),bnd 不会自动将任何包添加到“Import-Package”语句中。我花了一点时间才弄清楚。
  • @TinusTate Bndtools 明确警告您这一点,并告诉您在 Import-Package 列表的末尾添加 catch all 模式“*”。
【解决方案2】:

我认为这里的问题是您没有指定捆绑包使用的正确包/类集(使用清单中的 Import-Packages 指令)。除非 OSGi 知道这些,否则它真的无能为力!

不确定您是如何构建 OSGi 包的,但您应该查看 Maven bundle plugin,它解决了显式指定 Import-Packages 的问题(至少对于编译时的问题)。见http://wso2.org/library/tutorials/develop-osgi-bundles-using-maven-bundle-plugin#Importing%20packages。

【讨论】:

  • +1。补充一点:Maven Bundle Plugin 基于 Bnd,所以我在回答中所说的关于使用 Bnd 的所有内容也适用于 Maven Bundle Plugin。如果您的构建当前不是基于 Maven,则无需迁移到 Maven 即可获得此功能。
【解决方案3】:

我不是在回答中心问题,而是为类似问题提供我的解决方案。

就我而言,我有这样的类结构:

  • interface javax.script.ScriptEngineFactory
  • class pkga.A implements ScriptEngineFactory
  • class pkgb.B extends A

我的主要项目代码在类 B 中,而这个扩展类 A 在依赖 Jar 中。使用

<Export-Package>pkgb.*</Export-Package> 

不够,我收到一个错误,抱怨缺少javax.script.ScriptEngineFactory。这很奇怪,因为它是标准 JDK 8 的一部分,请注意包中的代码 pkgb 没有明确 引用 javax.script.*;也许 Manifest 编写者不知道需要导出这个接口?

我发现对 Export-Package 指令的这个添加解决了这个问题

<Export-Package>pkgb.*,javax.script.*</Export-Package>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    • 2011-04-23
    • 2015-06-05
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多