1

所以这是我的问题:

我有一些代码在 DocuShare 服务器上发生某个事件时被调用。我在自己的事件监听器中监听事件。到目前为止一切顺利,这没有问题。

此侦听器将调用单独开发并驻留在其自己的 jar 文件中的其他代码。

目前,我们总是不得不关闭整个系统以部署其中一个 jar 的新版本以便可以使用它的开销。

所以现在我正在尝试创建一个系统,将该 jarfile(不在类路径上)复制到另一个临时位置(所以没有 jarlock),将 jarfile 加载到它自己不同的类加载器中并执行它。这样,当开发新版本时,我可以简单地覆盖原始 jarfile。然后代码将查看是否对 jarfile 进行了修改,如果是,则执行相同的步骤。

我已经在一个更简单的设置(调用一个 servlet)中成功地做到了这一点,所以我知道“热部署”罐子的方法是有效的。

但是,在这种情况下,代码可以正常工作,直到我开始使用单独的类加载器。我可以找到 jarfile 并检查差异并相应地加载 jarfile,但是当我尝试访问该类时,我不再在 System.out 或 System.err 中获得任何输出。jar 中的代码没有正确执行,但我不明白为什么。

额外信息:代码正在其自己的线程中执行

发生的事情概述:

  1. DocuShare 发送事件
  2. 我的听众接听了这个事件
  3. 监听器(实现 java.util.concurrent.Executor)启动一个新线程(Runnable impl)
  4. Runnable impl 创建一个新的类加载器,然后检查文件夹内是否有新版本的 jar 文件,如果有,则将其复制到另一个目录,如果没有,则使用现有版本,将其加载到新的类路径中类加载器并执行它
  5. 从我使用新的 ClassLoader 加载类的那一刻起,我看不到 System.out/System.err 中打印的任何行。

代码示例(在 Runnable.run() 方法中):

URLClassLoader hotCL = new URLClassLoader(((URLClassLoader) systemCL).getURLs()); //new URLclassloader with URLs from system CL

//the following approach for putting the class on the classpath comes from another SO question from somebody else
Method m = cl.getClass().getDeclaredMethod("addURL", new Class[]{URL.class});
m.setAccessible(true);
m.invoke(cl, jar.toURI().toURL());
String cp = System.getProperty("java.class.path");
if (cp != null) {
    cp += File.pathSeparatorChar + jar.getCanonicalPath();
} else {
    cp = jar.toURI().getPath();
}

Logger.log(">>>>>>>> instantiating impl");  //this is printed in the System.out
Class<?> clsService = hotCL.loadClass(strService);  //strService is the class inside the separate jar
Object instance = clsService.newInstance();

Logger.log(">>>>>>>>>>>> class: " + clsService.getClass().toString()); //this is not printed in the System.out, neither is any log-statement after this or any error
//after this a method of the class instance is called but the code doesn't do anything.  Possibly an error but there's no error/stacktrace

关于 ClassLoaders 我有什么遗漏吗?我只是不明白为什么我没有看到任何错误或正在执行的代码。

4

1 回答 1

1

当您的类加载器尝试加载从您的动态类引用的 JDK 类时,它可能会挂起,因为它需要一个能够加载 JDK 类的父类加载器。您可以从当前上下文中借用一个功能父级,即:

new URLClassLoader(urls, this.getClass().getClassLoader())

如果您在重新加载已经实例化的类后遇到问题,请查看此线程。

于 2013-06-23T05:19:30.747 回答