如何在 Java 中更改 CLASSPATH?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/252893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you change the CLASSPATH within Java?
提问by pupeno
How do you change the CLASSPATH of a Java process from within the Java process?
如何从 Java 进程内部更改 Java 进程的 CLASSPATH?
Before you ask me "Why would you want to do that?" I'll explain it shortly.
在你问我“你为什么要这样做之前?” 我将很快解释它。
When you have a Clojure REPL running it is common to need more jars in your CLASSPATH to load a Clojuresource 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).
当您运行 Clojure REPL 时,通常需要在您的 CLASSPATH 中使用更多 jars 来加载Clojure源文件,我想这样做而不必重新启动 Clojure 本身(在 Slime 上使用它时这不是一个真正的选择在 Emacs 上)。
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.
这就是原因,但我不希望这个问题被标记为一些奇怪的语言一些奇怪的编辑器而被大多数可能有答案的 Java 开发人员所忽视。
采纳答案by VonC
Update Q4 2017: as commentedbelow by vda8888, in Java 9, the System java.lang.ClassLoader
is no longer a java.net.URLClassLoader
.
2017 年第四季度更新:正如vda8888在下面评论的那样,在 Java 9 中,系统java.lang.ClassLoader
不再是java.net.URLClassLoader
.
See "Java 9 Migration Guide: The Seven Most Common Challenges"
请参阅“ Java 9 迁移指南:七大最常见的挑战”
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 aURLClassLoader
anymore, so the occasional(URLClassLoader) getClass().getClassLoader()
or(URLClassLoader) ClassLoader.getSystemClassLoader()
sequences will no longer execute.
我刚刚描述的类加载策略是在一种新类型中实现的,而在 Java 9 中,应用程序类加载器就是这种类型。
这意味着它URLClassLoader
不再是 a ,所以偶尔的(URLClassLoader) getClass().getClassLoader()
or(URLClassLoader) ClassLoader.getSystemClassLoader()
序列将不再执行。
java.lang.ModuleLayerwould be an alternative approach used in order to influence the modulepath(instead of the classpath). See for instance "Java 9 modules - JPMS basics".
java.lang.ModuleLayer将是用于影响模块路径(而不是类路径)的替代方法。参见例如“ Java 9 模块 - JPMS 基础知识”。
For Java 8 or below:
对于 Java 8 或更低版本:
Some general comments:
一些一般性评论:
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。
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-allmentions in the comments this example of extending the URLClassLoader
)
类加载器以分层方式工作......因此任何对类 X 进行静态引用的类都需要在与 X 相同的类加载器中加载,或者在子类加载器中加载。您不能使用任何自定义类加载器来使系统类加载器链接正确加载代码,如果之前没有这样做的话。因此,除了您找到的额外代码之外,您还需要安排在自定义 ClassLoader 中运行您的主应用程序代码。
(话虽这么说,破获,所有的评论中提到的这个例子扩展 URLClassLoader
)
And you might consider not writing your own ClassLoader, but just use URLClassLoader instead. Create a URLClassLoader with a url that are notin the parent classloaders url's.
您可能会考虑不编写自己的 ClassLoader,而只需使用 URLClassLoader。使用不在父类加载器 url 中的url 创建一个 URLClassLoader 。
URL[] url={new URL("file://foo")};
URLClassLoader loader = new URLClassLoader(url);
A more complete solutionwould be:
一个更完整的解决方案将是:
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);
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;)):
如果你假设 JVM 系统类加载器是一个 URLClassLoader(这可能不适用于所有 JVM),你也可以使用反射来实际修改系统类路径......(但这是一个黑客;)):
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");
回答by Jon Skeet
I don't believe you can - the right thing to do (I believe) is create a new classloader with the new path. Alternatively, you could write your own classloader which allows you to change the classpath (for that loader) dynamically.
我不相信你可以 - 正确的做法(我相信)是用新路径创建一个新的类加载器。或者,您可以编写自己的类加载器,它允许您动态更改类路径(对于该加载器)。
回答by Hyman Leow
You may want to look into using java.net.URLClassLoader. It allows you to programmatically load classes that weren't originally in your classpath, though I'm not sure if that's exactly what you need.
您可能想考虑使用java.net.URLClassLoader。它允许您以编程方式加载最初不在类路径中的类,但我不确定这是否正是您所需要的。
回答by Henry B
It is possible as seen from the two links below, the method VonC gives seems to be the best but check out some of these posts and google for "Java Dynamic Classpath" or "Java Dynamic Class Loading" and find out some info from there.
从下面的两个链接可以看出,VonC 提供的方法似乎是最好的,但请查看其中一些帖子并在谷歌上搜索“Java 动态类路径”或“Java 动态类加载”,并从中找出一些信息。
I'd post in more depth but VonC has pretty much done the job.
我会更深入地发布,但 VonC 几乎完成了这项工作。
From Dynamic loading of class and Jar files.
Also check this sun forum post.
另请查看此sun 论坛帖子。
回答by myfreeweb
There's no need to write your own class loader! There's clojure.lang.DynamicClassLoader.
无需编写自己的类加载器!有clojure.lang.DynamicClassLoader。
http://blog.japila.pl/2011/01/dynamically-redefining-classpath-in-clojure-repl/
http://blog.japila.pl/2011/01/dynamically-redefining-classpath-in-clojure-repl/
回答by Akhi Youngisthan
String s="java -classpath abcd/ "+pgmname+" "+filename;
Process pro2 = Runtime.getRuntime().exec(s);
BufferedReader in = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
is an example of changin the classpath in java program
是在java程序中更改类路径的一个例子