【问题标题】:ClassLoader loads previous version of classes - JavaClassLoader 加载以前版本的类 - Java
【发布时间】:2014-09-21 20:37:08
【问题描述】:

我编写了一个插件,它获取类文件列表(由编译 Java 项目产生)作为输入,并运行与这些类相关的测试用例。我使用类加载器来加载类,并使用 JUnitCore() 来运行测试用例。下面的代码运行良好,输入类运行时没有问题。

Class<?> clazz =  Class.forName(className);     
Request request = Request.aClass(clazz);   
Result result = new JUnitCore().run(request);

然而,在我的程序中,上面的代码应该为类似的类运行数千次。为简单起见,假设我们只有一个类,第一步是编译该类,然后如果没有编译器错误将其复制到插件的 bin 目录,然后调用我的程序并检查它通过了所有测试用例。

在下一次迭代中,原始源代码会自动更改,然后编译,如果没有编译器错误,则复制并再次运行测试用例。这个过程可以运行数千次以获得所需的结果。 [在某些情况下甚至几个小时]

但是,问题在于类加载器使用了编译器类的第一个版本,并且在下一次迭代中它不会加载新版本并仍然使用之前的版本。我发现如果我在每次迭代中的 copy 指令之前添加一个 Thread.sleep(1000) ,那么它可以找到正确的版本。

首先,为什么我需要在复制之前而不是复制之后暂停?我希望在类加载器想要加载它们之前,文件在复制期间可能没有最终确定,并且类加载器使用以前的版本。但是,正如我所说,当我在复制之前添加暂停时,它可以正常工作,并且当我在复制之后添加暂停时它使用以前的版本。

其次,在我的程序中使用睡眠不是一个好主意。在最好的情况下,我的插件可能会工作几个小时才能找到所需的结果,如果我想在每次迭代中添加一个睡眠,那么需要几天的时间才能得到结果。因此,我更喜欢没有睡眠的解决方案。如果有人知道如何在没有 Thread.sleep 的情况下复制上述问题,请告诉我。

【问题讨论】:

  • ClassLoader 实际上不使用“previos”版本的类,它使用第一个版本的类,当它第一次加载时。如果类被加载,它不会被新的替换。你必须做一点魔法才能加载新版本。并且已经提出过此类问题,请使用搜索。
  • 当我添加睡眠时,它会使用正确的版本。
  • 如果它与 Thread.sleep() 一起工作,那么您必须提供您的代码示例,以便人们可以看到它并调试以理解。仅使用您编写的文本并没有真正的帮助。

标签: java classloader testcase


【解决方案1】:

我找到了解决方案。其实改程序后,我是先刷新项目,再复制文件。但是,问题在于 JDT 在复制之前不会重新编译和重建索引。所以我需要等rebuild完成,然后再做copy。这就是为什么复制前的 Thread.sleep 可以解决问题的原因。 但是,更好的解决方案是在刷新项目期间使用以下说明。

 try {
        project.refreshLocal(IResource.DEPTH_INFINITE, null); 

        IJobManager jobManager = Job.getJobManager();
        jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, null);
    } catch (CoreException | OperationCanceledException | InterruptedException  e) {
            e.printStackTrace();
    }

以上行解决了问题。

【讨论】:

    猜你喜欢
    • 2014-08-23
    • 1970-01-01
    • 2018-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多