注意:我对Java 9中引入的Module系统的经验很少。
我有一个Java进程,应该通过加载并通过反射执行它来运行另一个Jar文件。
请注意,两个Jar文件都依赖于JavaFX框架,该框架已从版本11中的JDK分离出来,因此可能会再次加载。
这里是适用于JDK版本8的原始版本:
val ideFile = File(binFolder, "Sk-IDE.jar")
val classLoader = ClassLoader.getSystemClassLoader() as URLClassLoader
val method = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java)
method.isAccessible = true
method.invoke(classLoader, ideFile.toURI().toURL())
val coreManager = Class.forName("com.skide.CoreManager")
val instance = coreManager.newInstance()
coreManager.getDeclaredMethod("bootstrap", Array<String>::class.java).invoke(instance, State.args)
(对addURL的反射调用是必需的,因为否则加载程序Jar无法加载其fxml文件)
这种方法在JDK 11上引发此异常:
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
的方法:val child = URLClassLoader(arrayOf(URL(ideFile.toURI().toURL().toString())), Installer::class.java.classLoader)
val coreManager = Class.forName("com.skide.CoreManager", true, child)
val instance = coreManager.newInstance()
Platform.runLater {
coreManager.getDeclaredMethod("bootstrap", Array<String>::class.java).invoke(instance, State.args)
}
引发与JavaFX相关的异常:
Exception in thread "JavaFX Application Thread" [20.11.2018 20:13:41 | ERROR] java.security.PrivilegedActionException: java.lang.reflect.InvocationTargetException
[20.11.2018 20:13:41 | ERROR] at java.base/java.security.AccessController.doPrivileged(Native Method)
[20.11.2018 20:13:41 | ERROR] at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
[20.11.2018 20:13:41 | ERROR] at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
[20.11.2018 20:13:41 | ERROR] at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
[20.11.2018 20:13:41 | ERROR] at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
[20.11.2018 20:13:41 | ERROR] at java.base/java.lang.Thread.run(Thread.java:834)
[20.11.2018 20:13:41 | ERROR] Caused by: java.lang.reflect.InvocationTargetException
[20.11.2018 20:13:41 | ERROR] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[20.11.2018 20:13:41 | ERROR] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[20.11.2018 20:13:41 | ERROR] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[20.11.2018 20:13:41 | ERROR] at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[20.11.2018 20:13:41 | ERROR] at com.skide.installer.Installer$start$2$1$1.run(Installer.kt:249)
[20.11.2018 20:13:41 | ERROR] at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
[20.11.2018 20:13:41 | ERROR] ... 6 more
[20.11.2018 20:13:41 | ERROR] Caused by: javafx.fxml.LoadException:
unknown path:9
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:105)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:930)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:980)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:227)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:752)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2450)
[20.11.2018 20:13:41 | ERROR] at com.skide.CoreManager$bootstrap$1.invoke(CoreManager.kt:47)
[20.11.2018 20:13:41 | ERROR] at com.skide.CoreManager$bootstrap$1.invoke(CoreManager.kt:24)
[20.11.2018 20:13:41 | ERROR] at com.skide.CoreManager.bootstrap(CoreManager.kt:136)
[20.11.2018 20:13:41 | ERROR] ... 12 more
[20.11.2018 20:13:41 | ERROR] Caused by: java.lang.ClassNotFoundException: com.skide.gui.controllers.SplashGuiController
[20.11.2018 20:13:41 | ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
[20.11.2018 20:13:41 | ERROR] at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
[20.11.2018 20:13:41 | ERROR] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
[20.11.2018 20:13:41 | ERROR] at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:928)
[20.11.2018 20:13:41 | ERROR] ... 21 more
解决此问题的最佳方法是什么?
问候,
丽兹3
编辑
在xtratic的帮助下,解决方案实际上很简单:
我只是将
child
URLClassloader添加到CoreManager#bootstrap反射调用中,即CoreManager(已加载jar)的bootstrap方法,然后将该URLClassloader传递给所有FXML加载器。 最佳答案
当您使用新的URLClassLoader
时,似乎在调用方法,但是抛出的javafx.fxml.LoadException
被PrivilegedActionException
和InvocationTargetException
包装。
即使您使用自己的URLClassloader
加载类,也似乎FXML解析器正在尝试使用内置的类加载器来加载FX bean,而后者并不了解FXML中的那些类。
您需要使FXMLLoader使用正确的类加载器,该类加载器包含fxml 引用的所有类。阅读FXMLLoader
的源代码,以了解如何处理类加载。如果可能,您可能需要修改库以执行fxml加载。查看FXMLLoader.setClassLoader(urlClassLoader)
或可能设置SecurityManager
,以便FXMLLoader
将使用调用的类加载器。FXMLLoader.java
/**
* Returns the classloader used by this serializer.
* @since JavaFX 2.1
*/
@CallerSensitive
public ClassLoader getClassLoader() {
if (classLoader == null) {
final SecurityManager sm = System.getSecurityManager();
final Class caller = (sm != null) ?
Reflection.getCallerClass() :
null;
return getDefaultClassLoader(caller);
}
return classLoader;
}
private static ClassLoader getDefaultClassLoader(Class caller) {
if (defaultClassLoader == null) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
final ClassLoader callerClassLoader = (caller != null) ?
caller.getClassLoader() :
null;
if (needsClassLoaderPermissionCheck(callerClassLoader, FXMLLoader.class.getClassLoader())) {
sm.checkPermission(GET_CLASSLOADER_PERMISSION);
}
}
return Thread.currentThread().getContextClassLoader();
}
return defaultClassLoader;
}
我猜测Java11可能已经更改了它的类加载器。
参见this link(内容粘贴在下面)
Exception in thread "main" java.lang.ClassCastException:
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader
cannot be cast to java.base/java.net.URLClassLoader
at monitor.Main.logClassPathContent(Main.java:46)
at monitor.Main.main(Main.java:28)