OSGi:如何确保类路径一致性?
根据 OSGi 文档,OSGi 旨在帮助防止 ClassPath 问题。
例如,来自“OSGi 的实际应用”:
启动应用程序时出现 ClassNotFoundExceptions,因为 类路径不正确。 OSGi 可以通过确保代码来提供帮助 在允许代码执行之前满足依赖关系。
然而,由于我们已将 Java 应用程序切换到 OSGi,因此我看到了比以往更多的 ClassNotFoundException,尤其是 NoClassDefFoundError。 OSGI 类加载器不再找到以前加载良好的类,更糟糕的是:您在运行时收到错误,这意味着您无法轻松检查它,除非手动测试应用程序的每个角落。
例如,我们的应用程序在 OSGi 下运行良好,但我们收到 Beta 测试人员的报告,称他们无法再将文档导出为 PDF。事实上,当我研究它时,我发现这个功能导致了一个异常被记录:
java.lang.NoClassDefFoundError: org/w3c/dom/Node
那么,OSGi 实际上创建的类路径问题比它解决的问题还要多吗?
更重要的是:我如何测试我的类路径与所有必要的导入包语句等是否一致。之前我在错误报告中阅读了它们?
According to the OSGi documentation, OSGi is designed to help prevent ClassPath problems.
For example, from "OSGi in action":
ClassNotFoundExceptions when starting your application because the
class path wasn't correct. OSGi can help by ensuring that code
dependencies are satisfied before allowing the code to execute.
However, since we've switched our java application to OSGi, I see more ClassNotFoundExceptions and especially NoClassDefFoundErrors than ever. Classes that were previously loading fine are not found anymore by the OSGI classloader, and worse: you get the error at run-time, which means that you can't easily check for it except by manually testing every corner of your application.
For example, our application was running happily under OSGi, but we received reports from beta testers that they couldn't export documents to PDF anymore. Indeed, when I looked into it, I found that this functionality caused an exception to be logged:
java.lang.NoClassDefFoundError: org/w3c/dom/Node
So, is OSGi actually creating more classpath problems than it solves?
and more importantly: How can I test that my class-path is consistent, with all necessary Import-Package statements etc. before I read about them in bug reports?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您的清单正确,OSGi 应用程序不会抛出 ClassNotFoundExceptions 和 NoClassDefFoundErrors。也就是说,您需要告诉 OSGi 您的捆绑包使用哪些包;如果您没有正确或诚实地执行此操作,那么 OSGi 无法帮助您。换句话说:GIGO(垃圾进,垃圾出)。
例如,您使用包
org.w3c.dom
,但未在Import-Package
语句中列出它。因此,OSGi 不知道您需要访问该包,因此当您实际尝试从该包加载类时,它们不可用。因此,您需要确保您的
Import-Package
语句对于您的捆绑包实际使用的包来说是准确的。好消息是“bnd”工具可以通过生成捆绑清单、使用字节码分析来查找所有静态引用的包来为您完成此操作。更新:
您的最后一个问题是在运行时发现问题之前如何测试您的捆绑包是否一致。 Bnd 有一个“验证”功能,可以做到这一点。实际上,如果您首先使用 Bnd 生成清单,那么您将不需要验证功能。但是,我对您的构建过程一无所知,因此您可能会发现短期内很难迁移到基于 Bnd 的构建...在这种情况下,将验证任务添加为后期任务会相对简单。构建后的处理步骤。不过,我仍然建议在构建过程的早期尝试使用 Bnd。
An OSGi application will not throw ClassNotFoundExceptions and NoClassDefFoundErrors if your manifest is correct. That is, you need to tell OSGi which packages your bundle uses; if you don't do this correctly or honestly, then OSGi cannot help you. In other words: GIGO (Garbage In, Garbage Out).
For example, you use the package
org.w3c.dom
but you do not list it in yourImport-Package
statement. Therefore OSGi does not know that you need access to that package, and so when you actually try to load classes from that package, they are not available.So, you need to make sure your
Import-Package
statement is accurate with respect to the packages your bundles actually use. The good news is that the "bnd" tool can do this for you by generating the bundle manifest, using bytecode analysis to find all the statically referenced packages.Update:
Your final question asks how to test that your bundles are consistent before discovering problems at runtime. Bnd has a "verify" feature that does exactly this. Actually if you use Bnd to generate the manifest in the first place, then you will not need the verify feature. However, I don't know anything about your build process so you might find it difficult to move to a Bnd-based build in the short term... in this case it would be relatively simple to add the verification task as a post-processing step after the build. However I would still recommend trying to use Bnd earlier in the build process.
我认为这里的问题是您没有指定捆绑包使用的正确的包/类集(使用 MANIFEST 中的 Import-Packages 指令)。除非 OSGi 了解这些,否则它真的无济于事!
不确定您如何构建 OSGi 捆绑包,但您应该查看 Maven 捆绑包插件,它解决了显式指定导入包的问题(至少对于编译时的包而言)。请参阅 http://wso2.org/库/教程/develop-osgi-bundles-using-maven-bundle-plugin#Importing%20packages。
I think the trouble here is that you are not specifying the correct set of packages/classes used by your bundle (using the Import-Packages directive in your MANIFEST). Unless OSGi knows about those, it really cannot help!
Not sure how you are building your OSGi bundles, but you should check out the
Maven bundle plugin
, that solves the problems of explicitly specifying Import-Packages (at least for the compile-time ones). See http://wso2.org/library/tutorials/develop-osgi-bundles-using-maven-bundle-plugin#Importing%20packages.我不是在回答核心问题,而是为类似问题提供解决方案。
在我的例子中,我有这样的类结构:
interface javax.script.ScriptEngineFactory
class pkga.A 实现 ScriptEngineFactory
class pkgb.B extends A
我的主要项目代码位于类
B
中,而此扩展类A
在一个依赖的 Jar 中。使用不够,我收到一条错误,抱怨缺少
javax.script.ScriptEngineFactory
。这很奇怪,因为它是标准 JDK 8 的一部分,请注意包pkgb
中的代码没有明确引用javax.script.*
;也许Manifest编写者不知道这个接口需要导出?我发现 Export-Package 指令的添加解决了问题
I am not answering the central question, but providing my solution for a similar problem.
In my case, I had this class structure:
interface javax.script.ScriptEngineFactory
class pkga.A implements ScriptEngineFactory
class pkgb.B extends A
My primary project code was in class
B
and this extended classA
in a dependent Jar. Usingwas insufficient, I received an error complaining about the lack of
javax.script.ScriptEngineFactory
. This is odd as it is part of standard JDK 8, note that code in packagepkgb
did not explicitly referencejavax.script.*
; perhaps the Manifest writer didn't know that this interface needed to be exported?I found this addition to the Export-Package directive solved the problem