有没有可能在运行时从Java设置一个环境variables?

是否有可能在运行时从Java应用程序设置环境variables? 在Java 1.5 java.lang.System类中有getenv()方法,我只需要一个setenv()方法…

是否有可能修改java进程本身的环境variables; 不在孩子的过程中。

可以通过JNI来实现吗? 那该怎么办?

谢谢。

编辑:好吧,让我这样说 – 我们可以用Java做以下事情。 请回答。

  1. 我们可以修改当前stream程的环境吗?
  2. 我们可以修改父进程的环境吗?
  3. 我们可以修改subprocess的环境吗?

Hemal Pandya回答说:“你可以修改当前和subprocess的环境,但不能修改产生这个进程的父进程。” 你同意吗?

如果我的直觉是正确的 ,并且实际上想要修改环境以利用生成的(fork)subprocess( Runtime.getRuntime().exec() ),则使用ProcessBuilder而不是exec() 。 您可以通过ProcessBuilder实例的environment()方法构build自定义环境。

如果这不是你想达到的目标,那么请不要理会这个答案。


UPDATE

三个更新的具体问题的答案如下:

  1. 我们可以修改当前stream程的环境吗?
    • 不容易 。 取决于是否要更改进程的环境,更改由同一个JVM中的System.getenv()返回的值。
    • 正如Greg Hewgill所指出的那样,要改变当前进程的环境,你可以通过JNI调用setenv或者其特定于平台的对等体。 您也可以使用下面第2点的非常复杂的方法,它适用于任何进程(只要您有权限)。但是,请注意,在大多数JVM中,此更改可能永远不会反映在System.getenv()返回的值中,因为在java.util.Map (或等价物)中,环境往往不是在虚拟机启动时caching的。
    • 要改变JVMcaching的环境副本,当使用caching时(请参阅System.java中的源代码,将用于部署的任何JVM发行版),您可以尝试对实现进行黑客攻击(通过类加载顺序, reflection ,或仪器) 。例如,对于SUN的v1.6 JVM,环境高速caching由未logging的ProcessEnvironment类(可以修补)进行pipe理。
  2. 我们可以修改父进程的环境吗?
    • 非常困难,而且非常不便携 。 如果你绝对而必要的话,你可以使用非常具体的黑客技巧:
      • Windows: dynamic添加/编辑远程进程的环境variables
      • * nix: 有没有办法改变另一个进程的环境variables? – 这是一个性能杀手,因为任何由gdb检测的进程将被暂停非零时间。
  3. 我们可以修改subprocess的环境吗?
    • 是的 ,在产生stream程时通过ProcessBuilder
    • 如果在需要进行环境变更时已经产生了这个过程,则需要上面的方法2 (或者一些同样复杂的方法,例如在产生时间的代码注入,由父进程通过例​​如套接字进一步控制)。

请注意,除了涉及ProcessBuilder方法之外,上述所有方法都很脆弱,容易出错,不可移植到不同程度,并且在multithreading环境中容易出现竞争状况。

针对您更新的问题:

  1. 我们可以修改当前stream程的环境吗?
    是的 ,如果你使用JNI调用setenv()或其他东西。 你可能不需要这样做,但它可能不适用于所有情况。
  2. 我们可以修改父进程的环境吗?
    没有
  3. 我们可以修改subprocess的环境吗?
    是的 ,使用ProcessBuilder

我不这么认为,至less不是纯粹的Java,但为什么你需要这样做呢? 在Java中,最好使用可以修改的System.getProperties()来使用属性。

如果你确实需要,我相信你可以把C setenv函数封装成一个JNI调用 – 事实上,如果有人已经这样做了,我不会感到惊讶。 但是我不知道代码的细节。

您可以修改当前进程和subprocess的环境,但不能修改产生此进程的父进程的环境。

您可以获得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(“”)调用来检索它。