所以这是我的问题:
我有一些代码在 DocuShare 服务器上发生某个事件时被调用。我在自己的事件监听器中监听事件。到目前为止一切顺利,这没有问题。
此侦听器将调用单独开发并驻留在其自己的 jar 文件中的其他代码。
目前,我们总是不得不关闭整个系统以部署其中一个 jar 的新版本以便可以使用它的开销。
所以现在我正在尝试创建一个系统,将该 jarfile(不在类路径上)复制到另一个临时位置(所以没有 jarlock),将 jarfile 加载到它自己不同的类加载器中并执行它。这样,当开发新版本时,我可以简单地覆盖原始 jarfile。然后代码将查看是否对 jarfile 进行了修改,如果是,则执行相同的步骤。
我已经在一个更简单的设置(调用一个 servlet)中成功地做到了这一点,所以我知道“热部署”罐子的方法是有效的。
但是,在这种情况下,代码可以正常工作,直到我开始使用单独的类加载器。我可以找到 jarfile 并检查差异并相应地加载 jarfile,但是当我尝试访问该类时,我不再在 System.out 或 System.err 中获得任何输出。jar 中的代码没有正确执行,但我不明白为什么。
额外信息:代码正在其自己的线程中执行
发生的事情概述:
- DocuShare 发送事件
- 我的听众接听了这个事件
- 监听器(实现 java.util.concurrent.Executor)启动一个新线程(Runnable impl)
- Runnable impl 创建一个新的类加载器,然后检查文件夹内是否有新版本的 jar 文件,如果有,则将其复制到另一个目录,如果没有,则使用现有版本,将其加载到新的类路径中类加载器并执行它
- 从我使用新的 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 我有什么遗漏吗?我只是不明白为什么我没有看到任何错误或正在执行的代码。