【问题标题】:Why does it appear that OSGi-classloading is being bypassed?为什么似乎绕过了 OSGi 类加载?
【发布时间】:2012-07-31 03:36:55
【问题描述】:

我目前正在努力为我们的 OSGi 捆绑包提供一些对 OSGi 非常不友好的第 3 方库。其中一个库(我已经使用 bnd 将其变成了一个包)设法加载它不应该加载的类(至少通过 OSGi 规则)。让我们假设 bundle 被称为Foo,它加载类的包被称为bar

Foo 具有 bar 作为可选导入。不过这无关紧要,因为没有导出 bar 的包。我没有使用任何引导委托。包含barjar 文件位于应用程序类路径中(OSGi 框架嵌入在我的应用程序中运行)。

显然Foo 以某种方式绕过了 OSGi 类加载基础架构。如何才能做到这一点?我很确定它不使用自定义类加载器,因为它没有理由拥有一个(没有功能Foo 提供需要这样的东西)。那么,bundle 可以使用哪些标准的、开箱即用的方法来绕过 OSGi 类加载?

【问题讨论】:

  • 抱歉跑题了,我正在为将 Felix 嵌入到我的应用程序中的非常相似的任务而“挣扎”,(实际上仍然有悬而未决的问题stackoverflow.com/questions/9822616/…),这不是很无礼的问题您共享代码如何嵌入(实际上是初始化 Felix)OSGi。先感谢您。您可以向我发送信息,甚至可以对 mvoronoy_at_gmail_com 做出负面回应
  • 我在 Pax Exam 测试中遇到了这些问题,所以我没有自己进行嵌入。我知道 Pax Exam 使用 Pax Runner,它应该更容易嵌入框架。不过我自己从来没有做过,所以我无法提供任何帮助。

标签: java osgi classloader


【解决方案1】:

您使用的是什么 OSGi 框架? 您是否有命令提示符命令或其他方式来请求有关包的详细信息? OSGi 规范允许您进行详细调查,并且大多数框架都为 OSGi PackageAdmin 和其他 API 提供了匹配的命令/接口。

其他 OSGi 框架也会发生这种情况吗?

如果你使用ProSyst's mBedded Server作为OSGi框架,你可以使用命令发现谁在从哪里加载什么

pkginfo [<package>[ <package>]] - 显示依赖关系 指定的包裹。如果没有参数,你会收到 有关框架中所有可用包的信息。

【讨论】:

  • 我正在使用嵌入式 Apache Felix。我还没有尝试过其他框架(但我会尝试)。
【解决方案2】:

如果类在应用程序类加载器上可用,这将起到作用:

BundleContext.class.getClassLoader().loadClass("bar.X")

如果您可以通过加载器加载任何类,则可以获取所有其他类。当然,如果您要运行安全性,您可以禁止访问类加载器。

【讨论】:

    【解决方案3】:

    好吧,以下是我没有证据的假设。

    实现非 OSGi 可选导入的最简单方法是使用 Class.forName(name) - 请注意没有 classLoader 的签名。让我们看一下源代码:

    return forName0(className, true, ClassLoader.getCallerClassLoader());
    

    反过来让我们看看ClassLoader.getCallerClassLoader()

    ...
    Class caller = Reflection.getCallerClass(3);
    ...
    

    3 - 是要调用的帧数(例如getCallerClass(0) - 将返回反射类)。您可以轻松计算堆栈中#3 的代码,如果 OSGi 未加载它,它将使用默认的 classLoader。

    【讨论】:

    • 是的,但是由于包有一个自定义类加载器,它遵循 OSGi 规则,在正确实现的 OSGi fw 中,即使使用 Class.forName,您仍应保留在 OSGi 空间中,这不应该有可能我认为...
    • @pooh - 看看短语 OSGi-framework runs embedded in my application 这意味着有代码使用 OSGi 加载的类,但没有由 OSGi 加载。 (查找嵌入的定义:felix.apache.org/site/…)所以我们很可能有堆栈:[App Non OSGi]->[OSGi loaded]->[Class.forName] - 这正是#3
    • @Dewfy 你的计数是错误的。 0 -> Reflection.getCallerClass; 1 -> ClassLoader.getCallerClassLoader; 2->Class.forName; 3 -> Class.forName 的调用者。
    • Felix 似乎处理了一些不完全符合规范的类加载情况。参见例如issues.apache.org/jira/browse/FELIX-712 还有其他问题。由于这里 OSGi 嵌入在应用程序中,因此堆栈上有“非 OSGi”类,它可能会将所有类加载委托给系统类路径,而不仅仅是 Java.*,因为它通常应该......
    • 如果 Felix 框架不适合您,您可以禁用隐式启动委托。它的目的是尝试猜测何时存在需要引导委托的错误代码。一般来说,它运作良好。如果您发现无法正常工作的特定案例,您可以考虑在 Felix 报告问题。
    【解决方案4】:

    以下是推测,因为没有足够的信息来给出明确的答案。该库可能正在使用线程上下文类加载器 (TCCL)。如果bar 包对您自己的包可见(即,如果它是包中的私有包)并且您调用Foo 包,则可能已将TCCL 设置为允许加载bar 包从你的捆绑包中。

    要测试这个理论,请尝试更改代码以在调用 Foo 包之前将 TCCL 显式设置为 null:然后它会抛出 ClassNotFoundException

    【讨论】:

    • 我在负责的代码中找到了一个尝试使用 TCCL 的位置,但由于您描述的原因而失败。有趣的是,它直接使用系统类加载器作为故障转移。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多