【问题标题】:Add jar to classpath at runtime under java 9java 9下运行时添加jar到classpath
【发布时间】:2018-06-11 00:36:44
【问题描述】:

直到 以编程方式在运行时将外部 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 我们有问题:

线程“主”java.lang.ClassCastException 中的异常: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader 无法转换为 java.base/java.net.URLClassLoader

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

【问题讨论】:

  • 虽然发行说明中提到当前的 JavaSE/JDK 没有提供任何这样的 API 来在运行时增加类路径。然而,您越能详细说明您最终想要实现的目标,社区就能为您提供更多帮助。
  • ClassLoader.getSystemClassLoader() 不再是URLClassLoader,但您可以随时创建URLClassLoader 的新实例。
  • @ZhekaKozlov 是正确的,尤其是。如果您无论如何都可以通过反射调用 JAR 文件中的代码。
  • 实际上,使用 Java 9,您有两个问题。即使 ClassLoader 实际上是 URLClassLoader,我怀疑在模块化应用程序中是否允许尝试反射。
  • 我发现“Gradle”与 UrlClassLoader 有什么问题。有人知道他们是怎么解决的吗?

标签: java9 java jar classpath java-9 urlclassloader


【解决方案1】:

JavaSE9 release notes 读起来差不多:

应用程序类加载器不再是 java.net.URLClassLoader(从未有过的实现细节 在以前的版本中指定)。

假设代码 ClassLoader::getSytemClassLoader 返回一个 URLClassLoader 对象将 需要更新。

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

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

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

正如thread from Oracle 中所建议的那样。这带有警告:

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

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

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

【讨论】:

  • 好的。用什么来回报旧的?
  • @EvgeniyEgorov 您到底想达到什么目的才是真正的问题。如果你能详细说明一下,那会很有帮助。
  • 我试图在谷歌搜索中找到有关它的信息。不幸的是,我没有发现任何信息或文档。
  • @EvgeniyEgorov 您可能还想看看this thread 并确定您的要求。
【解决方案2】:

Naman 的答案不是您正在寻找的正确替代品。 在 Java 9 及以上版本中,在类路径中添加 jar 的正确方法是使用 Java InstrumentationappendToSystemClassLoaderSearch(JarFile jarfile) 方法。

首先,您需要将代理类添加到您的 MANIFEST.MF

Launcher-Agent-Class: com.yourpackage.Agent

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

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(); }
    }

}

【讨论】:

  • jdk12. agentmain(..) 没有被调用。 MANIFEST.MF 具有带有 Launcher-Agent-Class 的字符串。
猜你喜欢
  • 2018-06-27
  • 2020-07-09
  • 2016-06-26
  • 1970-01-01
  • 2020-05-21
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
相关资源
最近更新 更多