2013-04-15 12 views
3

我很困扰ClassLoader尝试解析仅在特定条件下工作的资源的情况。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") 

...有相同的结果。

这对我来说太奇怪了。任何用于调试或放弃此行为显示的指针都是值得赞赏的!

回答

2

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

作为标准OSGi的扩展,Equinox确实提供了称为ContextFinder的东西,它执行堆栈检查以尝试在调用堆栈中查找最顶层的OSGi包类加载器。然而,你几乎没有任何控制,结果可能会像你所看到的那样非常出人意料。当然,因为这是一个Equinox特定的扩展,任何依赖ContextFinder正常工作的代码都会在所有其他OSGi框架上失败。

因此,不要浪费时间去尝试调试,最好不要使用TCCL。如果你想一个资源相对加载到一个特定的类,然后实现它从字面类对象,例如:

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

UPDATESomeClass.class.getClass()

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

+0

谢谢,这指出我正确的方向!在JBehave中,我能够以不同的方式配置测试的执行。而不是使用[LoadFromClasspath]的默认构造函数(http://grepcode.com/file/repo1.maven.org/maven2/org.jbehave/jbehave-core/3.7.5/org/jbehave/core/io/LoadFromClasspath 。java#LoadFromClasspath),它使用TCCL,我现在用“我的”类实例化了LoadFromClasspath,现在类加载器能够找到所有的资源。 – AndreasEK