Java系统属性的范围
在Java中,我们使用System.setProperty()方法来设置一些系统属性。 根据这篇文章 ,使用系统属性是有点棘手。
System.setProperty()可能是一个邪恶的电话。
- 这是100%的线程敌对
- 它包含超全局variables
- 当这些variables在运行时神秘地改变时,debugging是非常困难的。
我的问题如下。
-
系统属性的范围如何? 它们是特定于每个虚拟机,还是具有“超级全局性质”,在每个虚拟机实例上共享同一组属性? 我猜想选项1
-
是否有任何工具可用于监视运行时更改以检测系统属性中的更改。 (只是为了方便问题检测)
系统属性的范围
至less通过阅读System.setProperties
方法的API规范,我无法得到系统属性是否被所有JVM实例共享的答案。
为了弄清楚,我写了两个快速的程序,通过System.setProperty
设置系统属性,使用相同的键,但不同的值:
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) {} } } }
(注意运行上面的两个程序会使它们陷入无限循环!)
事实certificate,当使用两个单独的java
进程运行这两个程序时,在一个JVM进程中设置的属性的值不会影响另一个JVM进程的值。
我应该补充的是,这是使用Sun的JRE 1.6.0_12的结果,而且这种行为至less在API规范中没有定义(或者我还没有find它),这些行为可能会有所不同。
是否有任何工具来监视运行时更改
不是我的知识。 但是,如果需要检查系统属性是否发生了变化,则可以一次保存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规范证实了这一点:
这个类是线程安全的:multithreading可以共享一个单独的
Properties
对象,而不需要外部同步, Serialized Form
系统属性是每个进程。 这意味着它们比静态字段更加全球化,这是每个类加载器。 例如,如果您有一个运行多个Java webapps的Tomcat实例,其中每个实例都有一个名为globalField的静态字段com.example.Example,那么这个webapps将共享系统属性,但com.example.Example。 globalField可以在每个webapp中设置为不同的值。
它们的范围是正在运行的JVM,但除非有一些深奥的类加载器问题,否则带有属性对象的静态variables将执行相同的操作,并有机会同步或执行其他任何您需要的操作。
每个虚拟机有一个属性的副本。 他们和其他静态(包括单身人士)有很多相同的问题。
我想,作为一个黑客,你调用System.setProperties
到一个Properties
的版本,根据上下文(线程,调用堆栈,一天中的时间等)的不同响应。 它也可以使用System.setProperty
logging任何更改。 您还可以设置SecurityManager
日志安全检查的相关权限。
是的,“系统属性”是每个虚拟机(虽然有一些“魔术”属性包含有关主机系统的信息,例如:“os.name”,“os.arch”等)。
至于你的第二个问题:我不知道这样的工具,但如果你担心邻居系统属性得到改变,你可以使用一个特殊的SecurityManager来防止(甚至跟踪)系统属性的变化。
你不会说使用系统属性的动机是什么。
我们使用Spring来进行configuration,并使用注入XML的属性文件来设置初始属性。 应用程序运行时对configuration的更改通过使用JMX进行。
当然,还有许多其他方法可以使用属性文件,基于xml的configuration等在Java中更改configuration。
当你启动一个新的JVM时,它会创build一个环境variables的副本,并在它的所有生命周期中使用它们。 所以如果你改变了这个环境,他们仍然会受到限制。 奇怪的行为,我遇到了,我正在调查是稍有不同的:如果我启动一个JVM声明一些环境variables(-D参数在cmd行)影响我的应用程序库中使用的行为。 但是,如果在java代码(它们是可见的)内部,我对它们进行了更改,似乎这些更改不会影响库的行为。 奇怪的是,我们在同一个JVM!