【问题标题】:Adding files to java classpath at runtime [duplicate]在运行时将文件添加到java类路径[重复]
【发布时间】:2010-11-03 21:34:55
【问题描述】:

是否可以在运行时将文件(不一定是 jar 文件)添加到 java 类路径。 具体来说,该文件已经存在于类路径中,我想要的是是否可以将此文件的修改副本添加到类路径中。

谢谢,

【问题讨论】:

  • 有没有办法删除 jar 文件?还是用更新的版本替换它?
  • 这甚至是重复的吗?链接的问题是关于罐子,而不仅仅是文件

标签: java runtime classpath


【解决方案1】:

您只能将文件夹或 jar 文件添加到类加载器。所以如果你有一个单独的类文件,你需要先把它放到合适的文件夹结构中。

Here 是一个相当丑陋的 hack,它在运行时添加到 SystemClassLoader:

import java.io.IOException;
import java.io.File;
import java.net.URLClassLoader;
import java.net.URL;
import java.lang.reflect.Method;

public class ClassPathHacker {

  private static final Class[] parameters = new Class[]{URL.class};

  public static void addFile(String s) throws IOException {
    File f = new File(s);
    addFile(f);
  }//end method

  public static void addFile(File f) throws IOException {
    addURL(f.toURL());
  }//end method


  public static void addURL(URL u) throws IOException {

    URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
    Class sysclass = URLClassLoader.class;

    try {
      Method method = sysclass.getDeclaredMethod("addURL", parameters);
      method.setAccessible(true);
      method.invoke(sysloader, new Object[]{u});
    } catch (Throwable t) {
      t.printStackTrace();
      throw new IOException("Error, could not add URL to system classloader");
    }//end try catch

   }//end method

}//end class

反射是访问受保护方法addURL所必需的。如果有 SecurityManager,这可能会失败。

【讨论】:

  • 感谢大家的回复,我猜我们也可以在类路径中添加一个普通文件(不是类或 jar 等...),但我怎么知道哪个会被选中up(最新添加的类路径或旧文件)
  • 啊,这是个问题。其中大部分是依赖于实现的,因此您实际上不必在同一个类加载器中使用相同名称的类(或其他资源)。
  • 如果你把它们放到单独的类加载器中,那么就有一个规范。通常父类加载器优先,对于 webapps 它有时是相反的(但仍然是明确定义的)。引导加载程序始终排在第一位。
  • 这会抛出 java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader
  • 请注意以后遇到此答案的任何人。此代码假定getSystemClassLoader() 返回的加载程序是URLClassLoader 的一个实例,而从Java 9 开始不再是这样。
【解决方案2】:

试穿这件尺码。

private static void addSoftwareLibrary(File file) throws Exception {
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
    method.setAccessible(true);
    method.invoke(ClassLoader.getSystemClassLoader(), new Object[]{file.toURI().toURL()});
}

这会编辑系统类加载器以包含给定的库 jar。它很丑陋,但它确实有效。

【讨论】:

  • 很好的答案。但是,我会对其进行一些编辑,使用可变参数使其更加简单。
  • 有效!我通过删除数组来减少它,因为参数是可变参数(现在?)所以不再需要数组了。
  • 请注意以后遇到此答案的任何人。此代码假定getSystemClassLoader() 返回的加载器是URLClassLoader 的一个实例,而从Java 9 起不再是这样。
【解决方案3】:

我这样做的方法是使用我自己的类加载器

URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
DynamicURLClassLoader dynalLoader = new DynamicURLClassLoader(urlClassLoader);

并创建以下类:

public class DynamicURLClassLoader extends URLClassLoader {

    public DynamicURLClassLoader(URLClassLoader classLoader) {
        super(classLoader.getURLs());
    }

    @Override
    public void addURL(URL url) {
        super.addURL(url);
    }
}

无需任何反思即可工作

【讨论】:

  • 这个解决方案对我来说听起来不错,但它不起作用(可能是因为我在 Tomcat webapp 中?)。尝试从包含在动态加载的 JAR 中的类中调用方法时,出现“找不到类”错误。其他解决方案确实有效,即使在 web 应用中也是如此。
  • 这不起作用,因为您创建了一个新的类加载器,其他类加载器仍然无法访问您添加到该类加载器的文件
  • 请注意以后遇到此答案的任何人。此代码假定getSystemClassLoader() 返回的加载程序是URLClassLoader 的一个实例,但在Java 9 中不再是这样。
【解决方案4】:

您可以尝试 java.net.URLClassloader 与更新的类所在的文件夹/ja​​r 的 url,并在创建新线程时使用它而不是默认的类加载器。

【讨论】:

    【解决方案5】:

    是的,我相信这是可能的,但您可能必须实现自己的类加载器。我从来没有做过,但那是我可能会考虑的路径。

    【讨论】:

      【解决方案6】:

      是的,你可以。如果您想将其隔离,则它需要位于其包结构中与其余已编译代码不同的目录中。然后,您只需将其基本目录放在命令行上类路径的前面。

      【讨论】:

        【解决方案7】:

        我的解决方案:

        File jarToAdd = new File("/path/to/file");
        
        new URLClassLoader(((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs()) {
            @Override
            public void addURL(URL url) {
                 super.addURL(url);
            }
        }.addURL(jarToAdd.toURI().toURL());
        

        【讨论】:

        • 除了提供代码之外,请解释您的代码的作用(在答案本身中,而不是在 cmets 中)。
        • 这不起作用,因为URLClassLoader 中的addURL 方法是protected。但是您可以编写自己的 URLClassLoader 来重写方法并且修饰符应该是可访问的。
        猜你喜欢
        • 1970-01-01
        • 2018-12-14
        • 2010-09-28
        • 1970-01-01
        • 2014-08-31
        • 1970-01-01
        • 1970-01-01
        • 2016-07-10
        • 1970-01-01
        相关资源
        最近更新 更多