60

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.

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).

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.

4

6 に答える 6

80

2017 年第 4 四半期の更新: vda8888によって以下にコメントされているように、Java 9 では、システムはもはや.java.lang.ClassLoaderjava.net.URLClassLoader

Java 9 移行ガイド: 最も一般的な 7 つの課題」を参照してください。

今説明したクラス・ローディング戦略は新しいタイプで実装され、Java 9 ではアプリケーション・クラス・ローダーがそのタイプです。
つまりURLClassLoader、これはもはや ではないため、時折の(URLClassLoader) getClass().getClassLoader()または(URLClassLoader) ClassLoader.getSystemClassLoader()シーケンスは実行されなくなります。

java.lang.ModuleLayerは、(クラスパスではなく)モジュールパスに影響を与えるために使用される代替アプローチです。たとえば、「Java 9 モジュール - JPMS の基本」を参照してください。


Java 8 以下の場合:

一般的なコメント:

システムクラスパスを変更することはできません (動作が保証されている移植可能な方法で、以下を参照)。代わりに、新しい ClassLoader を定義する必要があります。

ClassLoader は階層的に機能します...そのため、クラス X への静的参照を作成するクラスは、X と同じ ClassLoader または子 ClassLoader にロードする必要があります。カスタム ClassLoader を使用して、システム ClassLoader リンクによってロードされたコードを適切に作成することはできません。そのため、見つけた追加のコードに加えて、カスタム ClassLoader でメイン アプリケーション コードを実行するように調整する必要があります。
(そうは言っても、この拡張の 例のコメントでクラックされたすべての言及があります)URLClassLoader

また、独自の ClassLoader を作成するのではなく、代わりに URLClassLoader を使用することを検討することもできます。親クラスローダーの URL にないURL で URLClassLoader を作成します。

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 に当てはまるとは限りません)、リフレクションを使用して実際にシステム クラスパスを変更することもできます... (ただし、これはハックです;)):

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");
于 2008-10-31T09:37:34.727 に答える
3

あなたができるとは思いません-正しいこと(私は信じています)は、新しいパスで新しいクラスローダーを作成することです。または、(そのローダーの) クラスパスを動的に変更できる独自のクラスローダーを作成することもできます。

于 2008-10-31T08:49:32.173 に答える
2

独自のクラス ローダーを作成する必要はありません。clojure.lang.DynamicClassLoaderがあります。

http://blog.japila.pl/2011/01/dynamically-redefining-classpath-in-clojure-repl/

于 2011-07-20T11:57:47.000 に答える
1

以下の2つのリンクからわかるように、VonCが提供する方法が最適のようですが、これらの投稿のいくつかをチェックして、「JavaDynamicClasspath」または「JavaDynamicClassLoading」をグーグルで検索してそこから情報を見つけてください。

もっと詳しく投稿したいのですが、VonCはほとんどその仕事をしてくれました。

クラスおよびJarファイルの動的ロードから。

この太陽フォーラムの投稿も確認してください。

于 2008-10-31T10:23:37.287 に答える
1

java.net.URLClassLoaderの使用を検討することをお勧めします。クラスパスに元々含まれていなかったクラスをプログラムでロードできますが、それがまさに必要なものかどうかはわかりません。

于 2008-10-31T09:36:38.537 に答える