web-dev-qa-db-ja.com

Java内でCLASSPATHをどのように変更しますか?

Javaプロセス内からJavaプロセスのCLASSPATHをどのように変更しますか?


「なぜそんなことをしたいの?」と私に尋ねる前に。すぐに説明します。

Clojure REPL=を実行している場合、 Clojure ソースファイルをロードするためにCLASSPATHでさらにjarが必要になることがよくあります。 Clojure自体を再起動します(EmacsのSlimeでClojureを使用する場合、これは実際にはオプションではありません)。

それが理由ですが、この質問を奇妙な言語のいくつかの奇妙なエディタとしてタグ付けし、多くのJava開発者が答えを持っているかもしれません。

59
pupeno

2017年第4四半期の更新: コメント 以下 vda8888 、in Java 9、システム Java.lang.ClassLoaderJava.net.URLClassLoader

Java 9 Migration Guide:The Seven Most Common Challenges 」を参照してください

先ほど説明したクラスローディング戦略は新しいタイプで実装され、Java 9ではアプリケーションクラスローダーはそのタイプです。
これはURLClassLoaderではないことを意味するため、ときどき(URLClassLoader) getClass().getClassLoader()または(URLClassLoader) ClassLoader.getSystemClassLoader()シーケンスは実行されなくなります。

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


Java 8以下の場合:

一般的なコメント:

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

ClassLoaderは階層的に機能します...クラスXへの静的参照を作成するクラスは、Xと同じClassLoaderまたは子ClassLoaderにロードする必要があります。カスタムClassLoaderを使用して、システムClassLoaderリンクによってロードされたコードを適切にロードすることはできません(以前にそうしなかった場合)。そのため、見つけた余分なコードに加えて、カスタムClassLoaderでメインアプリケーションコードを実行するように手配する必要があります。
(つまり、 cracked-all は、この例の extending the URLClassLoader にコメントで言及しています)

また、独自のClassLoaderを記述するのではなく、代わりにURLClassLoaderを使用することを検討することもできます。親クラスローダーのURLにnotの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");
78
VonC

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

3
Jon Skeet

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

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

2
myfreeweb

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

1
Jack Leow

以下の2つのリンクからわかるように、VonCが提供する方法が最適と思われますが、これらの投稿のいくつかを調べて、「Java Dynamic Classpath」または「Java Dynamic Class Loading」についてgoogleで調べて、そこから情報を見つけてください。

私はより詳細に投稿したいと思いますが、VonCはほとんど仕事をしました。

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

これも確認してください Sunフォーラム投稿

1
Henry B