Javaでは、System.setProperty()メソッドを使用していくつかのシステムプロパティを設定しています。 この記事 によると、システムプロパティの使用は少し注意が必要です。
System.setProperty()は悪質な呼び出しになる可能性があります。
- それは100%スレッド敵対的です
- スーパーグローバル変数が含まれています
- これらの変数が実行時に不可解に変化する場合、デバッグは非常に困難です。
私の質問は次のとおりです。
システムプロパティのスコープはどうですか?それらはすべての仮想マシンに固有のものですか、それともすべての仮想マシンインスタンスで同じプロパティセットを共有する「スーパーグローバル」の性質を持っていますか?私はオプションを推測します1
システムプロパティの変更を検出するためにランタイムの変更を監視するために使用できるツールはありますか? (問題検出を簡単にするため)
システムプロパティのスコープ
少なくとも System.setProperties
メソッドのAPI仕様を読んだところ、JVMのすべてのインスタンスでシステムプロパティが共有されているかどうかを確認できませんでした。
調べるために、同じキーを使用して値が異なるSystem.setProperty
を介してシステムプロパティを設定する2つの簡単なプログラムを作成しました。
class T1 {
public static void main(String[] s) {
System.setProperty("dummy.property", "42");
// Keep printing value of "dummy.property" forever.
while (true) {
System.out.println(System.getProperty("dummy.property"));
try {
Thread.sleep(500);
} catch (Exception e) {}
}
}
}
class T2 {
public static void main(String[] s) {
System.setProperty("dummy.property", "52");
// Keep printing value of "dummy.property" forever.
while (true) {
System.out.println(System.getProperty("dummy.property"));
try {
Thread.sleep(500);
} catch (Exception e) {}
}
}
}
(上記の2つのプログラムを実行すると、プログラムが無限ループになることに注意してください!)
2つの別個のJava
プロセスを使用して2つのプログラムを実行すると、1つのJVMプロセスで設定されたプロパティの値は、他のJVMプロセスの値に影響を与えないことがわかりました。
これはSunのJRE 1.6.0_12を使用した結果であり、この動作は少なくともAPI仕様で定義されていない(またはそれを見つけることができなかった)ため、動作が異なる場合があることを付け加えておきます。
ランタイムの変更を監視するツールはありますか
私の知る限りではありません。ただし、システムプロパティに変更があったかどうかを確認する必要がある場合は、Properties
のコピーを一度に保持し、それをSystem.getProperties
への別の呼び出しと比較できます-後すべて、 Properties
は Hashtable
のサブクラスなので、比較は同様の方法で実行されます。
以下は、システムプロパティに変更があったかどうかを確認する方法を示すプログラムです。おそらくエレガントな方法ではありませんが、その仕事をしているようです:
import Java.util.*;
class CheckChanges {
private static boolean isDifferent(Properties p1, Properties p2) {
Set<Map.Entry<Object, Object>> p1EntrySet = p1.entrySet();
Set<Map.Entry<Object, Object>> p2EntrySet = p2.entrySet();
// Check that the key/value pairs are the same in the entry sets
// obtained from the two Properties.
// If there is an difference, return true.
for (Map.Entry<Object, Object> e : p1EntrySet) {
if (!p2EntrySet.contains(e))
return true;
}
for (Map.Entry<Object, Object> e : p2EntrySet) {
if (!p1EntrySet.contains(e))
return true;
}
return false;
}
public static void main(String[] s)
{
// System properties prior to modification.
Properties p = (Properties)System.getProperties().clone();
// Modification of system properties.
System.setProperty("dummy.property", "42");
// See if there was modification. The output is "false"
System.out.println(isDifferent(p, System.getProperties()));
}
}
プロパティはスレッドセーフではありませんか?
Hashtable
はスレッドセーフなので、Properties
も同様になり、実際には、 Properties
クラスのAPI仕様で確認します。
このクラスはスレッドセーフです。外部同期を必要とせずに、複数のスレッドが単一の
Properties
オブジェクトを共有できます。 Serialized Form
システムプロパティはプロセスごとです。これは、クラスローダーごとの静的フィールドよりもグローバルであることを意味します。したがって、たとえば、Tomcatの単一のインスタンスで複数のJava webappsを実行している場合、それぞれにクラスcom.example.Example
globalField
という名前の静的フィールドを使用すると、webappsはシステムプロパティを共有しますが、com.example.Example.globalField
は、Webアプリケーションごとに異なる値に設定できます。
VMごとにプロパティのコピーが1つあります。それらには、他の静力学(シングルトンを含む)とほとんど同じ問題があります。
ハックとして、コンテキスト(スレッド、コールスタック、時刻など)に応じて異なる応答をするProperties
のバージョンに対してSystem.setProperties
を呼び出すと思います。 System.setProperty
を使用して変更を記録することもできます。また、関連する権限のSecurityManager
logsセキュリティチェックを設定することもできます。
はい。「システムプロパティ」はVMごとです(ただし、「os.name」、「os.Arch」など、ホストシステムに関する情報を含む「マジック」プロパティは多数あります)。
2番目の質問については、私はそのようなツールを認識していませんが、システムプロパティが変更されることを懸念している場合は、特別な SecurityManager を使用してシステムプロパティの変更を防止(およびおそらく追跡)することができます。
それらのスコープは実行中のJVMですが、難解なクラスローダーが発行されていない限り、プロパティオブジェクトを使用した静的変数は同じことを行い、同期または他の必要なことを行う機会があります。
新しいJVMを開始すると、環境変数のコピーが作成され、その変数がライフサイクル全体で使用されます。したがって、その環境に変更を加えても、それらはその環境に限定されたままになります。私が遭遇し、調査している奇妙な動作は少し異なります。JVMを起動すると、アプリケーションで使用するライブラリの動作に影響を与えるいくつかの環境変数(cmd行の-D引数)を宣言します。しかし、Javaコード(それらが表示されている場所)内)に変更を加えた場合、これらの変更はライブラリの動作に影響を与えないようです。奇妙なことに、同じJVM!
システムプロパティを使用する動機は何ですか。
Springを構成に使用し、XMLに挿入されるプロパティファイルを使用して初期プロパティを設定します。アプリの実行中に構成を変更するには、JMXを使用します。
もちろん、Javaプロパティファイル、xmlベースの構成などを使用して)で構成を変更する方法は他にもたくさんあります。