web-dev-qa-db-ja.com

Javaから実行時に環境変数を設定することは可能ですか?

実行時に環境変数をJava application?から設定できますか?Java 1.5 Java.lang.Systemクラスにはgetenv()メソッドがあります。 setenv()メソッドのみが必要です...

Javaプロセス自体で、子プロセスではなく、環境変数を変更することは可能ですか?.

JNIで達成することは可能ですか?そして、それはどのように機能しますか?

ありがとう。

編集:Okこのように言えば-Javaで次のことができます。答えてください。

  1. 現在のプロセスの環境を変更できますか?
  2. 親プロセスの環境を変更できますか?
  3. 子プロセスの環境を変更できますか?

Hemal Pandyaは、「現在のプロセスと子プロセスの環境は変更できますが、このプロセスを生成した親プロセスの環境は変更できません」と回答しています。これに同意しますか?

42
Vicky

私の直感が正しい場合、実際に環境を変更して、生成された(分岐した)サブプロセスのために環境を変更したい場合(Runtime.getRuntime().exec())、exec()の代わりに ProcessBuilder を使用します。 ProcessBuilderインスタンスの environment() メソッドを使用して、カスタム環境を構築できます。

これがnotである場合は、この回答を無視してください。


[〜#〜] update [〜#〜]

更新された3つの具体的な質問に対する回答は次のとおりです。

  1. 現在のプロセスの環境を変更できますか?
    • 簡単ではありません。プロセスの環境を変更するか、同じJVMでSystem.getenv()によって返される値を変更するか、またはその両方を変更するかによって異なります。
    • Greg Hewgillが指摘したように、現在のプロセスの環境を変更するには、setenvまたはそのプラットフォーム固有の同等物をJNI経由で呼び出すことができます。また、以下のpoint 2)から非常に複雑な方法を使用することもできます。これは、任意のプロセスで機能します(権限がある場合)。ただし、ほとんどのJVMでは、環境は_Java.util.Map_(または同等のもの)での仮想マシンの起動時にキャッシュされないことが多いため、この変更がSystem.getenv()によって返される値に決して反映されないことに注意してください。
    • JVMのキャッシュされた環境のコピーを変更するには、キャッシュが使用されている場合(デプロイに使用するJVMディストリビューションの_System.Java_のソースコードを参照)、実装のハッキングを試みることができます(クラスの読み込み順序を介して、 reflection 、または instrumentation 。)たとえば、Sunのv1.6 JVMの場合、環境キャッシュは文書化されていないProcessEnvironmentクラス(これはパッチを適用できます。)
  2. 親プロセスの環境を変更できますか?
  3. 子プロセスの環境を変更できますか?
    • はい、プロセスを生成するときにProcessBuilderを介して。
    • 環境の変更が必要なときにプロセスが既に生成されている場合、method 2上記(またはコードなどの同様に複雑な方法) -スポーン時の注入。親プロセスによるソケットなどを介して外部から制御されます。)

ProcessBuilderを含むメソッドを除く上記のすべてのメソッドは、脆弱で、エラーが発生しやすく、さまざまな程度に移植できず、マルチスレッド環境で競合状態になりやすいことに注意してください。

34
vladr

更新された質問に対する回答:

  1. 現在のプロセスの環境を変更できますか?
    はい、JNIを使​​用してsetenv()または何かを呼び出す場合。ただし、おそらくこれを行う必要はなく、すべての状況で機能するとは限りません。
  2. 親プロセスの環境を変更できますか?
    いいえ
  3. 子プロセスの環境を変更できますか?
    はいProcessBuilderを使用。
6
Greg Hewgill

ProcessEnvironmentが保持している基礎となるマップのハンドルを取得し、新しいものを入れて必要なものをすべて削除できます。

これはJava 1.8.0_144で動作します。Javaの他のバージョンで動作することを保証できませんが、実行時に環境を本当に変更する必要がある場合はおそらく同様です。

private static Map<String,String> getModifiableEnvironment() throws Exception{
    Class pe = Class.forName("Java.lang.ProcessEnvironment");
    Method getenv = pe.getDeclaredMethod("getenv");
    getenv.setAccessible(true);
    Object unmodifiableEnvironment = getenv.invoke(null);
    Class map = Class.forName("Java.util.Collections$UnmodifiableMap");
    Field m = map.getDeclaredField("m");
    m.setAccessible(true);
    return (Map) m.get(unmodifiableEnvironment);
}

マップへの参照を取得したら、必要なものを追加するだけで、通常の古いSystem.getenv( "")呼び出しを使用してマップを取得できます。

Os Java version 1.8_161の両方でWindowsで動作しないMACで動作するようにこれを試しました

5

少なくともJavaの場合はそうではありませんが、なぜそうする必要があるのでしょうか? Javaでは、変更可能なSystem.getProperties()を介してプロパティを使用することをお勧めします。

本当に必要な場合は、C setenv関数をJNI呼び出しでラップできると確信しています。実際、誰かが既にそうしていても驚かないでしょう。ただし、コードの詳細はわかりません。

1
David Z

現在のプロセスと子プロセスの環境を変更できますが、このプロセスを生成した親プロセスの環境は変更できません。

0