如何在 Java 中更改 CLASSPATH? [英] How do you change the CLASSPATH within Java?

查看:54
本文介绍了如何在 Java 中更改 CLASSPATH?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从 Java 进程内部更改 Java 进程的 CLASSPATH?

How do you change the CLASSPATH of a Java process from within the Java process?

在你问我你为什么要这样做之前?"我将很快解释它.

Before you ask me "Why would you want to do that?" I'll explain it shortly.

当您运行 Clojure REPL 时,通常需要在 CLASSPATH 中使用更多 jar 来加载 Clojure 源文件,并且我想这样做而不必重新启动 Clojure 本身(在 Emacs 上的 Slime 上使用它时,这不是一个真正的选择).

When you have a Clojure REPL running it is common to need more jars in your CLASSPATH to load a Clojure source file, and I'd like to do it without having to restart Clojure itself (which is not really an option when using it on Slime on Emacs).

这就是原因,但我不希望这个问题被标记为一些奇怪的语言一些奇怪的编辑器而被大多数可能有答案的 Java 开发人员忽视.

That's the reason but I don't want this question tagged as some-weird-language some-weird-editor and be disregarded by the majority of Java developers that may have the answer.

推荐答案

2017 年第四季度更新:如 vda8888在下面评论,在Java 9中,系统java.lang.ClassLoader 不再是 java.net.URLClassLoader.

Update Q4 2017: as commented below by vda8888, in Java 9, the System java.lang.ClassLoader is no longer a java.net.URLClassLoader.

请参阅Java 9 迁移指南:七个最常见的挑战"

我刚刚描述的类加载策略是在一种新类型中实现的,而在 Java 9 中,应用程序类加载器就是这种类型.
这意味着它不再是 URLClassLoader,所以偶尔出现 (URLClassLoader) getClass().getClassLoader()(URLClassLoader) ClassLoader.getSystemClassLoader()code> 序列将不再执行.

The class loading strategy that I just described is implemented in a new type and in Java 9 the application class loader is of that type.
That means it is not a URLClassLoader anymore, so the occasional (URLClassLoader) getClass().getClassLoader() or (URLClassLoader) ClassLoader.getSystemClassLoader() sequences will no longer execute.

java.lang.ModuleLayer将是用于影响 modulepath (而不是类路径)的替代方法.参见例如Java 9 模块 - JPMS 基础知识".

java.lang.ModuleLayer would be an alternative approach used in order to influence the modulepath (instead of the classpath). See for instance "Java 9 modules - JPMS basics".

对于 Java 8 或更低版本:

For Java 8 or below:

一些一般性评论:

您不能(以保证工作的可移植方式,见下文)更改系统类路径.相反,您需要定义一个新的 ClassLoader.

you cannot (in a portable way that's guaranteed to work, see below) change the system classpath. Instead, you need to define a new ClassLoader.

ClassLoader 以分层方式工作......因此任何对类 X 进行静态引用的类都需要在与 X 相同的类加载器中加载,或者在子类加载器中加载.您不能使用任何自定义 ClassLoader 使系统 ClassLoader 链接正确加载代码,如果之前没有这样做的话.因此,除了您找到的额外代码之外,您还需要安排在自定义 ClassLoader 中运行您的主应用程序代码.
(话虽如此,
cracked-all 在评论中提到了这个 扩展URLClassLoader)

ClassLoaders work in a hierarchical manner... so any class that makes a static reference to class X needs to be loaded in the same ClassLoader as X, or in a child ClassLoader. You can NOT use any custom ClassLoader to make code loaded by the system ClassLoader link properly, if it wouldn't have done so before. So you need to arrange for your main application code to be run in the custom ClassLoader in addition to the extra code that you locate.
(That being said, cracked-all mentions in the comments this example of extending the URLClassLoader)

并且您可能会考虑不编写自己的 ClassLoader,而只需使用 URLClassLoader.创建一个 URLClassLoader,其 url not 在父类加载器的 url 中.

And you might consider not writing your own ClassLoader, but just use URLClassLoader instead. Create a URLClassLoader with a url that are not in the parent classloaders url's.

URL[] url={new URL("file://foo")};
URLClassLoader loader = new URLClassLoader(url);

更完整的解决方案是:

ClassLoader currentThreadClassLoader
 = Thread.currentThread().getContextClassLoader();

// Add the conf dir to the classpath
// Chain the current thread classloader
URLClassLoader urlClassLoader
 = new URLClassLoader(new URL[]{new File("mtFile").toURL()},
                      currentThreadClassLoader);

// Replace the thread classloader - assumes
// you have permissions to do so
Thread.currentThread().setContextClassLoader(urlClassLoader);

如果你假设 JVM 系统类加载器是一个 URLClassLoader(这可能不适用于所有 JVM),你也可以使用反射来实际修改系统类路径......(但这是一个黑客;)):

If you assume the JVMs system classloader is a URLClassLoader (which may not be true for all JVMs), you can use reflection as well to actually modify the system classpath... (but that's a hack;)):

public void addURL(URL url) throws Exception {
  URLClassLoader classLoader
         = (URLClassLoader) ClassLoader.getSystemClassLoader();
  Class clazz= URLClassLoader.class;

  // Use reflection
  Method method= clazz.getDeclaredMethod("addURL", new Class[] { URL.class });
  method.setAccessible(true);
  method.invoke(classLoader, new Object[] { url });
}

addURL(new File("conf").toURL());

// This should work now!
Thread.currentThread().getContextClassLoader().getResourceAsStream("context.xml");

这篇关于如何在 Java 中更改 CLASSPATH?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆