【发布时间】:2022-01-01 02:57:38
【问题描述】:
我有一个使用以下解决方案在运行时动态加载 jar 文件的应用程序:
File file = ...
URL url = file.toURI().toURL();
URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, url);
这是使用How to load JAR files dynamically at Runtime?的答案完成的
我现在想要一个适用于 JDK11+ 的解决方案,它与我使用的原始解决方案等效。因此,无需第三方库/框架或加载/调用单个类即可以编程方式进行。
我尝试了以下方法:
- 创建了一个扩展 UrlClassLoader 的 DynamicClassLoader:
public final class DynamicClassLoader extends URLClassLoader {
public DynamicClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public DynamicClassLoader(String name, ClassLoader parent) {
super(name, new URL[0], parent);
}
public DynamicClassLoader(ClassLoader parent) {
this("classpath", parent);
}
public void addURL(URL url) {
super.addURL(url);
}
}
- 然后我用 java.system.class.loader 标志启动我的应用程序:
java -Djava.system.class.loader=com.example.DynamicClassLoader
然后我有一个 jar 文件作为路径对象,我使用以下方法调用它:
public void loadJar(Path path) throws Exception {
URL url = path.toUri().toURL();
DynamicClassLoader classLoader = (DynamicClassLoader)ClassLoader.getSystemClassLoader();
Method method = DynamicClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, url);
}
调用此方法时,我得到以下强制转换类异常:
class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class com.example.classloader.DynamicClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader is
in module java.base of loader 'bootstrap'; com.example.classloader.DynamicClassLoader is in unnamed module of loader 'app')
我在 OpenJDK11(内部版本 11.0.10+9)上使用 Spring Boot (2.4)。
【问题讨论】:
-
您在启动时是否收到有关自定义类加载器的任何输出?
-
不特别。唯一记录的是这样的参数:arg=-Dfile.encoding=UTF-8 arg=-Djava.system.class.loader=DynamicClassLoader,但没有进一步的记录。在 dev 上有一条消息“org.springframework.boot.devtools.restart.classloader.RestartClassLoader - Created Restart ClassLoader”,但这不是在 prod 上(并且对工作/错误没有影响)。
-
我刚试过,这个系统属性仍然有效。您可以添加日志语句以查看您的类是否被加载+初始化,以及构造函数是否被调用等。但是您为什么要使用反射来调用您自己的
public方法DynamicClassLoader .addURL?并且真的有必要将jar添加到系统类加载器中,你不能通过新的URLClassLoader加载类吗? -
当然,要使
java.system.class.loader工作,指定的类必须能够被标准类加载器加载。您没有提到您的类加载器是以非标准方式存储的,但是这应该如何工作呢?除此之外,你没有回答这个问题。是的,使用URLClassLoader是一种常见的方式。如果你以官方的方式使用它,通过创建一个新的URLClassLoader,你不需要反射,它仍然可以工作。所以,还有一个悬而未决的问题是,你是否真的需要将jar添加到系统类加载器,而不能使用官方的方式。
标签: java jar classloader java-11