有没有可能在运行时从Java设置一个环境variables?
是否有可能在运行时从Java应用程序设置环境variables? 在Java 1.5 java.lang.System类中有getenv()方法,我只需要一个setenv()方法…
是否有可能修改java进程本身的环境variables; 不在孩子的过程中。
可以通过JNI来实现吗? 那该怎么办?
谢谢。
编辑:好吧,让我这样说 – 我们可以用Java做以下事情。 请回答。
- 我们可以修改当前stream程的环境吗?
- 我们可以修改父进程的环境吗?
- 我们可以修改subprocess的环境吗?
Hemal Pandya回答说:“你可以修改当前和subprocess的环境,但不能修改产生这个进程的父进程。” 你同意吗?
如果我的直觉是正确的 ,并且实际上想要修改环境以利用生成的(fork)subprocess( Runtime.getRuntime().exec()
),则使用ProcessBuilder而不是exec()
。 您可以通过ProcessBuilder
实例的environment()方法构build自定义环境。
如果这不是你想达到的目标,那么请不要理会这个答案。
UPDATE
三个更新的具体问题的答案如下:
- 我们可以修改当前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理。
- 不容易 。 取决于是否要更改进程的环境,更改由同一个JVM中的
- 我们可以修改父进程的环境吗?
- 非常困难,而且非常不便携 。 如果你绝对而必要的话,你可以使用非常具体的黑客技巧:
- Windows: dynamic添加/编辑远程进程的环境variables
- * nix: 有没有办法改变另一个进程的环境variables? – 这是一个性能杀手,因为任何由
gdb
检测的进程将被暂停非零时间。
- 非常困难,而且非常不便携 。 如果你绝对而必要的话,你可以使用非常具体的黑客技巧:
- 我们可以修改subprocess的环境吗?
- 是的 ,在产生stream程时通过
ProcessBuilder
。 - 如果在需要进行环境变更时已经产生了这个过程,则需要上面的方法2 (或者一些同样复杂的方法,例如在产生时间的代码注入,由父进程通过例如套接字进一步控制)。
- 是的 ,在产生stream程时通过
请注意,除了涉及ProcessBuilder
方法之外,上述所有方法都很脆弱,容易出错,不可移植到不同程度,并且在multithreading环境中容易出现竞争状况。
针对您更新的问题:
- 我们可以修改当前stream程的环境吗?
是的 ,如果你使用JNI调用setenv()
或其他东西。 你可能不需要这样做,但它可能不适用于所有情况。 - 我们可以修改父进程的环境吗?
没有 。 - 我们可以修改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(“”)调用来检索它。