在 java 9 下的运行时将 jar 添加到类路径

2022-09-02 22:18:17

直到在运行时将外部jar添加到类路径中,每个人都以编程方式使用:

URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
method.invoke(sysloader, new Object[]{file.toURI().toURL()});

现在有了java9,我们遇到了问题:

线程“main” java.lang.ClassCastException 中的异常:java.base/jdk.internal.loader.ClassLoaders$AppClassLoader 不能强制转换为 java.base/java.net.URLClassLoader

URLClassLoader在 Java 9 中不再有效。现在在 jdk9 下,如何以编程方式将外部 jar 添加到运行时的类路径中?


答案 1

JavaSE9 发行说明大致相同:

应用程序类装入器不再是 的实例(在以前的发行版中从未指定过的实现细节)。java.net.URLClassLoader

假定 ClassLoader::getSytemClassLoader 返回对象的代码将需要更新。URLClassLoader

请注意,Java SE 和 JDK 不为应用程序或库提供 API,以便在运行时动态扩充类路径

此外,当需要扩展的类路径时,可以使用

Class<?> clazz = Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));

正如 Oracle 在此线程中建议的那样。这带来了警告:

  • java.util.ServiceLoader使用线程的 ClassLoader 上下文 Thread.currentThread().setContextClassLoader(specialloader);

  • java.sql.DriverManager确实支持调用类的 ClassLoader,-not- 线程的 ClassLoader。直接使用创建驱动程序Class.forName("drivername", true, new URLClassLoader(urlarrayofextrajarsordirs).newInstance();

  • javax.activation使用线程的 ClassLoader 上下文(对于 javax.mail 很重要)。


答案 2

纳曼的答案并不能正确替代你正在寻找的东西。在 Java 9 及更高版本中,将 jar 添加到类路径的正确方法是使用 Java Instrumentation 的方法。appendToSystemClassLoaderSearch(JarFile jarfile)

首先,您需要将代理类添加到清单中。中频

Launcher-Agent-Class: com.yourpackage.Agent

然后添加您的代理。下面的示例将允许您调用以将Jar添加到Java 8和9 +中的类路径中Agent.addClassPath(File f)

public class Agent {
    private static Instrumentation inst = null;

    // The JRE will call method before launching your main()
    public static void agentmain(final String a, final Instrumentation inst) {
        Agent.inst = inst;
    }

    public static boolean addClassPath(File f) {
        ClassLoader cl = ClassLoader.getSystemClassLoader();

        try {
            // If Java 9 or higher use Instrumentation
            if (!(cl instanceof URLClassLoader)) {
                inst.appendToSystemClassLoaderSearch(new JarFile(f));
                return;
            }

            // If Java 8 or below fallback to old method
            Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            m.setAccessible(true);
            m.invoke(cl, (Object)f.toURI().toURL());
        } catch (Throwable e) { e.printStackTrace(); }
    }

}

推荐