注意:我对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.LoadExceptionPrivilegedActionExceptionInvocationTargetException包装。
即使您使用自己的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)

10-06 09:33