问题描述
在如下的模块结构中:
项目
|-公共模块
|-app模块
-Djava.system.class.loader=org.project.common.CustomClassLoader
JVM参数设置为使用公共模块中定义自定义类加载器。在IDEA中运行一个Spring Boot项目,这可以完美地工作。找到自定义类加载器,将其设置为系统类加载器,一切正常。
编译一个可运行的JAR(使用没有任何定制属性的默认Spring-Boot-maven-plugin),JAR本身拥有所有类,并且在它的lib目录中是具有定制类加载器的公共JAR。但是,使用-Djava.system.class.loader=org.project.common.CustomClassLoader
运行JAR会导致以下异常java.lang.Error: org.project.common.CustomClassLoader
at java.lang.ClassLoader.initSystemClassLoader([email protected]/ClassLoader.java:1989)
at java.lang.System.initPhase3([email protected]/System.java:2132)
Caused by: java.lang.ClassNotFoundException: org.project.common.CustomClassLoader
at jdk.internal.loader.BuiltinClassLoader.loadClass([email protected]/BuiltinClassLoader.java:583)
at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass([email protected]/ClassLoaders.java:178)
at java.lang.ClassLoader.loadClass([email protected]/ClassLoader.java:521)
at java.lang.Class.forName0([email protected]/Native Method)
at java.lang.Class.forName([email protected]/Class.java:415)
at java.lang.ClassLoader.initSystemClassLoader([email protected]/ClassLoader.java:1975)
at java.lang.System.initPhase3([email protected]/System.java:2132)
为什么会发生这种情况?是否因为在Runnable JAR中,类加载器类位于lib目录中的jar中,所以类加载器试图在将lib类添加到类路径之前进行设置?除了将类加载器从公共模块移动到所有其他需要它的模块之外,我还能做什么吗?
编辑:我尝试将自定义类加载器类从公共模块移动到应用程序,但仍然收到相同的错误。这是怎么回事?
推荐答案
因为IDEA将模块放在类路径上,并且其中一个模块包含自定义类加载器。
差不多吧。库类没有添加到类路径中,但可运行的Spring Boot应用程序自己的自定义类加载器知道在哪里找到它们以及如何加载它们。
要更深入地了解java.system.class.loader
,请阅读ClassLoader.getSystemClassLoader()
的Javadoc(添加了枚举后略微重新格式化):
即您遇到了鸡和蛋的问题:为了在JVM初始化期间找到您的自定义类加载器,您需要使用尚未初始化的Spring Boot Runnable JAR类加载器。
如果您想知道上面所描述的Javadoc在实践中是如何实现的,请查看OpenJDKsource code of ClassLoader.initSystemClassLoader()
。
如果您坚持使用Runnable JAR,即使这样也无济于事。您可以执行以下任一操作:
- 运行您的应用程序,而不是将其压缩到可运行的JAR中,而是将其作为一个普通的Java应用程序运行,所有应用程序模块(尤其是包含自定义类加载器的模块)都位于类路径上。
- 将您的自定义类加载器提取到可运行JAR外部的单独模块中,并在运行可运行JAR时将其放在类路径上。
- 通过
Thread.setContextClassLoader()
左右设置您的自定义类加载器,而不是尝试将其用作系统类加载器(如果这是一个可行的选项)。
更新2020-10-28:在可执行Jar格式文档中,我在"Executable Jar Restrictions"下找到了:
这证实了我在上面所写的内容,特别是我关于使用线程上下文类加载器的最后一个要点。
这篇关于Spring Boot Runnable JAR无法找到通过java.system.class.loader JVM参数设置的类加载器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!