ClassLoader仅在特定线程中查找资源

时间:2013-04-15 15:51:11

标签: osgi classloader executorservice jbehave rft

我正在努力解决ClassLoader尝试解析资源的问题,该资源仅在某些条件下有效。

用例如下:我将IBM Rational Functional Tester与JBehave结合使用进行自动验收测试。 JBehave将测试指定为纯文本故事文件。这些故事文件可以引用其他故事文件,因此被称为“给定故事”。 JBehave使用ExecutorService来执行可能具有多线程的故事。虽然JBehave加载文本文件没有问题(使用ClassLoader.getResourceAsStream),但它无法在从ExecutorService启动的线程中找到相同的文件。

行动中的ClassLoader是ContextFinder。在调试应用程序并挂起两个线程时,最初启动JBehave的“主线程”和从执行程序服务启动的“故事线程”运行故事文件,我可以确定类加载器的实例是相同的。还有父母的实例等。

但是打电话给

Thread.currentThread().getContextClassLoader().getResource("HelloWorld.story")

在主线程中完美运行,对于故事线程失败并返回null。

从ContextFinder的源代码判断,似乎它几乎没有收集堆栈上的类的所有ClassLoader。所以我尝试了这个:

SomeClass.class.getClass().getClassLoader().getResource("HelloWorld.story")

......结果相同。

这对我来说太奇怪了。任何用于调试或解释为什么会出现此行为的指针都表示赞赏!

1 个答案:

答案 0 :(得分:2)

线程上下文类加载器(TCCL)在OSGi中基本上是未定义的。你应该避免使用它。

作为标准OSGi的扩展,Equinox提供了一个名为ContextFinder的东西,它执行堆栈检查以尝试在调用堆栈中找到最顶层的OSGi bundle类加载器。然而,你几乎无法控制,结果可能是你所看到的意外。当然,由于这是一个特定于Equinox的扩展,任何依赖于ContextFinder正常工作的代码都将在所有其他OSGi框架上失败。

因此,不要浪费时间尝试调试,最好不要使用TCCL。如果要加载相对于特定类的资源,请从文字类对象中执行,例如:

MyClass.class.getResource("HelloWorld.story");

<强>更新

我在原始问题中注意到了这一点:SomeClass.class.getClass()。结果将是java.lang.Class本身的类对象。调用getClassLoader()总是返回JVM引导类加载器....可能不是你想要的!