是否可以在运行时通过Java设置环境变量?
是否可以在运行时从Java设置环境变量应用?在Java 1.5 java.lang.System类中,有getenv()方法,我会只需要一个setenv()方法...
是否可以在java进程本身中修改环境变量? 不在子进程中。
是否可以通过JNI实现它? 那将如何工作?
谢谢。
编辑:好的,让我这样说-我们可以使用Java进行以下操作。 请回答。
- 我们可以修改当前流程的环境吗?
- 我们可以修改父流程的环境吗?
- 我们可以修改子进程的环境吗?
Hemal Pandya回答说:“您可以修改当前进程和子进程的环境,但不能修改产生此进程的父进程的环境。” 你同意吗?
如果我的直觉是正确的,并且您实际上想修改环境以产生(分叉)子流程(Runtime.getRuntime().exec()
),请使用ProcessBuilder而不是ProcessBuilder
。您可以通过ProcessEnvironment
实例的environment()构建自定义环境。 方法。
如果这不是您要实现的目标,请忽略此答案。
更新
您的三个更新的特定问题的答案如下:
- 我们可以修改当前流程的环境吗?
- 不容易。 取决于您是否要更改进程的环境,更改同一JVM中
ProcessBuilder
返回的值或两者。 - 正如Greg Hewgill指出的那样,要更改当前流程的环境,您可以通过JNI调用
ProcessBuilder
或特定于平台的等效项。 您还可以从下面的第2点开始采用极为复杂的方法,该方法适用于任何进程(前提是您拥有权限。)但是,请注意,在大多数JVM中,作为环境,这种更改可能永远不会反映在ProcessEnvironment
返回的值中 通常会在虚拟机启动时在java.util.Map
(或等效文件)中缓存。 - 要更改JVM的环境的缓存副本,请使用缓存(请参见
ProcessBuilder
中的源代码,无论您将使用哪个JVM发行版进行部署),都可以尝试破解实现(通过类加载顺序,反射或检测) 。)例如,对于SUN的v1.6 JVM,环境缓存由未记录的ProcessEnvironment
类(您可以对其进行修补)进行管理。
- 不容易。 取决于您是否要更改进程的环境,更改同一JVM中
- 我们可以修改父流程的环境吗?
- 非常困难,而且高度不可移植。 如果绝对必要,则可以使用一些非常具体的技巧:
- Windows:动态添加/编辑远程进程的环境变量
- * nix:是否可以更改另一个进程的环境变量? -这是一个性能杀手,因为
ProcessBuilder
检测到的任何进程都将被暂停非零时间。
- 非常困难,而且高度不可移植。 如果绝对必要,则可以使用一些非常具体的技巧:
- 我们可以修改子进程的环境吗?
- 是的,请在生成过程时通过
ProcessBuilder
进行操作。 - 如果在需要更改环境时已经生成了该进程,则需要上面的方法2(或一些同样复杂的方法,例如在生成时进行代码注入,由父进程通过套接字最终控制)。
- 是的,请在生成过程时通过
请注意,除了涉及ProcessBuilder
的一种方法以外,上述所有方法都很脆弱,容易出错,无法移植到不同程度以及在多线程环境中容易出现竞争情况。
针对您的更新问题:
- 我们可以修改当前流程的环境吗?
是的,如果您使用JNI拨打setenv()
之类的话。 但是,您可能不需要执行此操作,并且它不一定在所有情况下都有效。 - 我们可以修改父流程的环境吗?
没有。 - 我们可以修改子进程的环境吗?
是的,使用ProcessBuilder
。
您可以在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(“”)调用来检索它。
我试过了,这在两个操作系统的Java版本1.8_161中都无法在Windows中的MAC中工作
我不这么认为,至少不是纯粹在Java中,但是为什么要这样做呢? 在Java中,最好通过setenv
使用属性,您可以对其进行修改。
如果确实需要,我确定您可以将C setenv
函数包装在JNI调用中-实际上,如果有人已经这样做了,我也不会感到惊讶。 我不知道代码的细节。
您可以修改当前进程和子进程的环境,但不能修改产生该进程的父进程的环境。