首页 > 解决方案 > Java 11 在运行时添加依赖 jar 的问题

问题描述

从 Java 8 迁移到 Java 11 时,出现以下错误:

Caused by: java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')

引发错误的代码:

URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
...
//URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
...
getMethod().invoke(urlClassLoader, new Object[] { url });

通过根据此链接创建 ClassLoader 加载 jar 时修复了上述错误: Java 9,与 ClassLoader.getSystemClassLoader 的兼容性问题

这是代码:

public class DynamicClassLoader extends URLClassLoader {

public DynamicClassLoader(URL[] urls, ClassLoader parent) {
    super(urls, parent);
}

public void addURL(URL url) {
    super.addURL(url);
}

public DynamicClassLoader(String name, ClassLoader parent) {
    super(name, new URL[0], parent);
}

/*
 * Required when this classloader is used as the system classloader
 */
public DynamicClassLoader(ClassLoader parent) {
    this("classpath", parent);
}

public DynamicClassLoader() {
    this(Thread.currentThread().getContextClassLoader());
}

public static DynamicClassLoader findAncestor(ClassLoader cl) {
    do {

        if (cl instanceof DynamicClassLoader)
            return (DynamicClassLoader) cl;

        cl = cl.getParent();
    } while (cl != null);

    return null;
}

/*
 *  Required for Java Agents when this classloader is used as the system classloader
 */
@SuppressWarnings("unused")
private void appendToClassPathForInstrumentation(String jarfile) throws IOException {
    addURL(Paths.get(jarfile).toRealPath().toUri().toURL());
}

}

使用以下方法加载罐子:

urlClassLoader.addURL(url);

运行 jar

-Djava.system.class.loader=com.ltchie.util.DynamicClassLoader 

但是在编译时添加的实用程序 jar(jpf.jar - Java 插件框架)在运行时无法在动态加载的 jar 中找到类并得到 ClassNotFoundException。代码:

Plugin plugin = pluginManager.getPlugin(pluginDescriptor.getId());

错误:

15:25:54,015 INFO  [AppApplication] >>>>>>>> loadLibraries() - ClassLoader: com.app.util.DynamicClassLoader@2f67b837  ... 
    
java.lang.NoClassDefFoundError: org/app/plugin/AppCommandPlugin
    at java.base/java.lang.ClassLoader.defineClass1(Native Method) 
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016) 
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174) 
    at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:550) 
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458) 
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:452) 
    at java.base/java.security.AccessController.doPrivileged(Native Method) 
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:451) 
    at org.java.plugin.standard.StandardPluginClassLoader.loadLocalClass(StandardPluginClassLoader.java:395) 
    at org.java.plugin.standard.StandardPluginClassLoader.loadPluginClass(StandardPluginClassLoader.java:464) 
    at org.java.plugin.standard.StandardPluginClassLoader.loadClass(StandardPluginClassLoader.java:372) 
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) 
    at org.java.plugin.standard.StandardPluginLifecycleHandler.createPluginInstance(StandardPluginLifecycleHandler.java:113) 
    at org.java.plugin.standard.StandardPluginManager.activatePlugin(StandardPluginManager.java:402) 
    at org.java.plugin.standard.StandardPluginManager.getPlugin(StandardPluginManager.java:217) 
    at org.app.command.AppApplication.getPlugin(AppApplication.java:253) 
    at org.app.command.AppApplication.execute(AppApplication.java:228) 
    at org.app.command.AppApplication.execute(AppApplication.java:221) 
    at org.app.command.AppApplication.startApplication(AppApplication.java:113) 
    at org.java.plugin.boot.Boot.boot(Boot.java:346) 
    at org.java.plugin.boot.Boot.main(Boot.java:243) 
    at org.app.plugin.boot.TPFBoot.main(TPFBoot.java:112)
 Caused by: java.lang.ClassNotFoundException: org.app.plugin.AppCommandPlugin 
    at org.java.plugin.standard.StandardPluginClassLoader.loadClass(StandardPluginClassLoader.java:378) 
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    ... 22 more

当我在我的 jar 清单中添加这个 jar 时,它可以工作。但是我需要在运行时加载,因为这个 java 命令行应用程序是基于 JPF 的,当我们运行使用 JPF 的应用程序 jar 时,我们需要加载很多 jars。

在进一步检查时,注意到 pluginManager 类与另一个类加载器:

16:57:14,000 INFO  [AppApplication] ############ pluginManager.getPlugin: jdk.internal.loader.ClassLoaders$AppClassLoader@799f7e29

这个 pluginManager 实例来自 jpf.jar 中可用的父类,该父类在我的应用程序 jar 清单的编译时 jar 依赖项中定义。所以我的应用程序使用类加载器 DynamicClassLoader 运行并将运行时 jar 加载到其中。但是清单中添加的依赖 jar 使用默认的 AppClassLoader 导致无法找到我的类。

任何人,请提出一个解决方案。

标签: javajava-11

解决方案


推荐阅读