java - 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 导致无法找到我的类。
任何人,请提出一个解决方案。
解决方案
推荐阅读
- google-sheets - 根据条件格式复制列中的特定值
- angular - 在带有角度的选择中加载默认选项
- proxy - 如何抑制代理链消息
- jenkins-pipeline - 为什么 Jenkins 使用正确的 AWS CLI 语法标记错误?
- parallel-processing - 使用并行执行时 Fortran 循环崩溃
- rust - 无法在迭代器上的 for 循环中移出借用的内容
- oracle - 如果我正在搜索的变量不存在的 if 语句?
- javascript - 跨域上传图片
- java - OWL API 无法解析的 YAGO 本体
- python - 使用朴素贝叶斯获取 TF/Count 向量