gpt4 book ai didi

java - Spring boot runnable jar 找不到通过 java.system.class.loader jvm 参数设置的类加载器

转载 作者:行者123 更新时间:2023-12-04 11:26:40 25 4
gpt4 key购买 nike

在这样的模块结构中:
项目
|
|- 常用模块
|- 应用模块
在 app 模块具有公共(public)模块作为依赖项的情况下,我在公共(public)模块中定义了一个自定义类加载器类。应用模块有一个 -Djava.system.class.loader=org.project.common.CustomClassLoader jvm 参数集以使用在公共(public)模块中定义的自定义类加载器。
在 IDEA 中运行一个 spring boot 项目,这非常有效。找到自定义类加载器,设置为系统类加载器,一切正常。
编译一个可运行的 jar(使用没有任何自定义属性的默认 spring-boot-maven-plugin),jar 本身包含所有类,并且在它的 lib 目录中是具有自定义类加载器的公共(public) jar。但是,使用 -Djava.system.class.loader=org.project.common.CustomClassLoader 运行 jar导致以下异常

java.lang.Error: org.project.common.CustomClassLoader
at java.lang.ClassLoader.initSystemClassLoader(java.base@12.0.2/ClassLoader.java:1989)
at java.lang.System.initPhase3(java.base@12.0.2/System.java:2132)
Caused by: java.lang.ClassNotFoundException: org.project.common.CustomClassLoader
at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@12.0.2/BuiltinClassLoader.java:583)
at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@12.0.2/ClassLoaders.java:178)
at java.lang.ClassLoader.loadClass(java.base@12.0.2/ClassLoader.java:521)
at java.lang.Class.forName0(java.base@12.0.2/Native Method)
at java.lang.Class.forName(java.base@12.0.2/Class.java:415)
at java.lang.ClassLoader.initSystemClassLoader(java.base@12.0.2/ClassLoader.java:1975)
at java.lang.System.initPhase3(java.base@12.0.2/System.java:2132)

为什么会发生这种情况?是因为在可运行的 jar 中,类加载器类位于 lib 目录中的 jar 中,因此类加载器试图在将 lib 类添加到类路径之前进行设置?除了将类加载器从 common 移动到所有其他需要它的模块之外,我还能做些什么吗?
编辑 :我已经尝试将自定义类加载器类从通用模块移动到应用程序,但我仍然遇到相同的错误。这里发生了什么?

最佳答案

Running a spring boot project within IDEA this works perfectly. The custom classloader is found, set as a system classloader and everything works.


因为 IDEA 将您的模块放在类路径上,其中之一包含自定义类加载器。

Is it because in the runnable jar the classloader class is in a jar in lib directory so the classloader is trying to get set before the lib classes were added to the classpath?


的种类。 lib 类没有“添加到类路径”,但可运行的 Spring Boot 应用程序自己的自定义类加载器知道在哪里可以找到以及如何加载它们。
深入了解 java.system.class.loader , 请阅读 ClassLoader.getSystemClassLoader() 的 Javadoc (稍微重新格式化并添加了枚举):
  1. If the system property java.system.class.loader is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader.
  2. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent.
  3. An instance is then created using this constructor with the default system class loader as the parameter.
  4. The resulting class loader is defined to be the system class loader.
  5. During construction, the class loader should take great care to avoid calling getSystemClassLoader(). If circular initialization of the system class loader is detected then an IllegalStateException is thrown.

这里的决定性因素是 #3:用户定义的系统类加载器由默认系统类加载器加载。后者当然不知道如何从嵌套的 JAR 加载内容。只有在 JVM 完全初始化并且 Spring Boot 的特殊应用程序类加载器启动之后,才能读取那些嵌套的 JAR。
IE。您在这里遇到了鸡与蛋的问题:为了在 JVM 初始化期间找到您的自定义类加载器,您需要使用尚未初始化的 Spring Boot 可运行 JAR 类加载器。
如果您想知道上面描述的 Javadoc 是如何在实践中完成的,请查看 OpenJDK source code of ClassLoader.initSystemClassLoader() .

Is there anything I can do besides moving the classloader from common to all the other modules that need it?


如果您坚持使用可运行的 JAR,即使这样也无济于事。您可以做的是以下任一操作:
  • 运行您的应用程序,而不将其压缩到一个可运行的 JAR 中,而是作为一个普通的 Java 应用程序,在类路径上包含所有应用程序模块(尤其是包含自定义类加载器的模块)。
  • 将您的自定义类加载器提取到可运行 JAR 之外的单独模块中,并在运行可运行 JAR 时将其放在类路径中。
  • 通过 Thread.setContextClassLoader() 设置您的自定义类加载器左右而不是尝试将其用作系统类加载器,如果这是一个可行的选择。

  • 2020-10-28 更新:在文档“可执行 Jar 格式”中,我在 "Executable Jar Restrictions" 下找到了这个:

    System classLoader: Launched applications should use Thread.getContextClassLoader() when loading classes (most libraries and frameworks do so by default). Trying to load nested jar classes with ClassLoader.getSystemClassLoader() fails. java.util.Logging always uses the system classloader. For this reason, you should consider a different logging implementation.


    这证实了我上面写的内容,尤其是我关于使用线程上下文类加载器的最后一个要点。

    关于java - Spring boot runnable jar 找不到通过 java.system.class.loader jvm 参数设置的类加载器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64388395/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com