是否可以在运行时通过Java设置环境变量?

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

是否可以在java进程本身中修改环境变量? 不在子进程中。

是否可以通过JNI实现它? 那将如何工作?

谢谢。

编辑:好的,让我这样说-我们可以使用Java进行以下操作。 请回答。

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

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

Vicky asked 2020-08-12T10:30:14Z
5个解决方案
35 votes

如果我的直觉是正确的,并且您实际上想修改环境以产生(分叉)子流程(Runtime.getRuntime().exec()),请使用ProcessBuilder而不是ProcessBuilder。您可以通过ProcessEnvironment实例的environment()构建自定义环境。 方法。

如果这不是您要实现的目标,请忽略此答案。


更新

您的三个更新的特定问题的答案如下:

  1. 我们可以修改当前流程的环境吗?
    • 不容易。 取决于您是否要更改进程的环境,更改同一JVM中ProcessBuilder返回的值或两者。
    • 正如Greg Hewgill指出的那样,要更改当前流程的环境,您可以通过JNI调用ProcessBuilder或特定于平台的等效项。 您还可以从下面的第2点开始采用极为复杂的方法,该方法适用于任何进程(前提是您拥有权限。)但是,请注意,在大多数JVM中,作为环境,这种更改可能永远不会反映在ProcessEnvironment返回的值中 通常会在虚拟机启动时在java.util.Map(或等效文件)中缓存。
    • 要更改JVM的环境的缓存副本,请使用缓存(请参见ProcessBuilder中的源代码,无论您将使用哪个JVM发行版进行部署),都可以尝试破解实现(通过类加载顺序,反射或检测) 。)例如,对于SUN的v1.6 JVM,环境缓存由未记录的ProcessEnvironment类(您可以对其进行修补)进行管理。
  2. 我们可以修改父流程的环境吗?
    • 非常困难,而且高度不可移植。 如果绝对必要,则可以使用一些非常具体的技巧:
      • Windows:动态添加/编辑远程进程的环境变量
      • * nix:是否可以更改另一个进程的环境变量? -这是一个性能杀手,因为ProcessBuilder检测到的任何进程都将被暂停非零时间。
  3. 我们可以修改子进程的环境吗?
    • 是的,请在生成过程时通过ProcessBuilder进行操作。
    • 如果在需要更改环境时已经生成了该进程,则需要上面的方法2(或一些同样复杂的方法,例如在生成时进行代码注入,由父进程通过套接字最终控制)。

请注意,除了涉及ProcessBuilder的一种方法以外,上述所有方法都很脆弱,容易出错,无法移植到不同程度以及在多线程环境中容易出现竞争情况。

vladr answered 2020-08-12T10:31:28Z
6 votes

针对您的更新问题:

  1. 我们可以修改当前流程的环境吗?
    是的,如果您使用JNI拨打setenv()之类的话。 但是,您可能不需要执行此操作,并且它不一定在所有情况下都有效。
  2. 我们可以修改父流程的环境吗?
    没有。
  3. 我们可以修改子进程的环境吗?
    是的,使用ProcessBuilder
Greg Hewgill answered 2020-08-12T10:32:15Z
5 votes

您可以在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中工作

Narcoleptic Snowman answered 2020-08-12T10:32:54Z
1 votes

我不这么认为,至少不是纯粹在Java中,但是为什么要这样做呢? 在Java中,最好通过setenv使用属性,您可以对其进行修改。

如果确实需要,我确定您可以将C setenv函数包装在JNI调用中-实际上,如果有人已经这样做了,我也不会感到惊讶。 我不知道代码的细节。

David Z answered 2020-08-12T10:33:18Z
0 votes

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

Miserable Variable answered 2020-08-12T10:33:39Z
translate from https://stackoverflow.com:/questions/580085/is-it-possible-to-set-an-environment-variable-at-runtime-from-java