Java URLClassLoader可以';无法完成来自新线程的类加载请求

Java URLClassLoader可以';无法完成来自新线程的类加载请求,java,classloader,Java,Classloader,==背景== 我正在尝试为桌面java应用程序实现自动更新功能,该功能旨在使用某种管理器,该管理器可以决定从何处加载应用程序(即,我们是尝试加载新版本还是跟上当前版本)。为此,我创建了使用URLClassLoader的引导程序 ==情况== 我有以下工件: bootstrapper.jar app.jar lib/*.jar bootstrapper.jar有自己的main()方法,清单文件引用入口点作为 Main-Class: ru.skarpushin.projects.bootstra

==背景==
我正在尝试为桌面java应用程序实现自动更新功能,该功能旨在使用某种管理器,该管理器可以决定从何处加载应用程序(即,我们是尝试加载新版本还是跟上当前版本)。为此,我创建了使用URLClassLoader的引导程序

==情况== 我有以下工件:

  • bootstrapper.jar
  • app.jar
  • lib/*.jar
bootstrapper.jar有自己的main()方法,清单文件引用入口点作为

Main-Class: ru.skarpushin.projects.bootstrapper.Bootstrapper
所以我可以通过调用命令行来运行它

javaw -jar bootsrapper.jar
app.jar这是主应用程序(基于Spring的应用程序),与第三方lib(位于lib文件夹中)有大量依赖关系,并从manifest.mf引用

Class-Path: lib/balloontip-1.2.3-SNAPSHOT.jar lib/commons-codec-1.6.ja
 r lib/commons-lang3-3.1.jar lib/commons-logging-1.1.1.jar lib/fluent-
 hc-4.2.1.jar lib/gson-2.2.2.jar lib/guava-11.0.2.jar lib/log4j-1.2.16
 .jar lib/org.springframework.asm-3.1.2.RELEASE.jar lib/org.springfram
lib/*.jar-一堆依赖项

==I用户类加载器的方式==

classLoader = new URLClassLoader(new URL[] { new File("app.jar").toURI().toURL() }, Thread.currentThread()
        .getContextClassLoader());
Thread.currentThread().setContextClassLoader(classLoader);
Class entryPointClass = classLoader.loadClass(entryPoint);
Method mainMethod = entryPointClass.getMethod("main", String[].class);
mainMethod.invoke(null, (Object) args);
==问题== 这对某些类非常有效,而对其他类则不行。问题是为什么以及如何解决这个问题

它看起来似乎与线程有某种联系。 让我们调用Thread1——应用程序启动时的主线程,以及我构造URLCalssLoader的地方。 所有在Thread1上加载类的请求都已成功完成,无论它们位于何处(无论是app.jar还是libs)。 在新创建的线程上加载类的所有请求(我们称之为ThreadN)都失败

有趣的是,我发现: -假设ThreadN无法加载ClassA -如果我更改代码,以便强制从Thread1加载ClassA,那么ThreadN上就不会有错误 -我检查了Thread1和ThreadN的上下文类加载器是否相同

所以在ThreadN上,我可以使用缓存类,但不能加载新类


有什么想法可以解决吗?

不幸的是,正是我的代码导致了这种行为

启动了Bootstrapper.main()方法;它打开URLClassLoader,加载应用程序入口点并调用它。所有这些都是在主线程中完成的。问题是,这是桌面java应用程序——一旦显示了主框架,代码就会被解锁,bootstrapper.main方法退出(应用程序仍在执行)

但在bootstrapper.main中,我确实有finally子句,在其中我显式调用URLClassLoader上的.close()方法,它强制它只使用缓存类,而不加载新类

} finally {
    try {
        classLoader.close();
    } catch (IOException e) {
        // failed to close. don't care. Should we?
    }
}

一旦我删除了这个代码,问题就消失了

“我正在尝试为桌面java应用程序实现自动更新功能”-我认为java webstart正是您想要的?我不是在考虑和评估选项。WebStart完全是另一回事,我的问题与此无关。但是谢谢你的建议。