如何从 Java 设置环境变量?

2022-08-31 04:45:50

如何从 Java 设置环境变量?我看到我可以使用 ProcessBuilder 为子流程执行此操作。不过,我有几个子流程要启动,所以我宁愿修改当前流程的环境,让子流程继承它。

有一个用于获取单个环境变量。我还可以使用 .但是,呼吁这样做会抛出一个 - 显然他们的意思是环境是只读的。而且,没有.System.getenv(String)MapSystem.getenv()put()MapUnsupportedOperationExceptionSystem.setenv()

那么,有没有办法在当前运行的进程中设置环境变量呢?如果是这样,如何?如果不是,理由是什么?(这是因为这是Java,因此我不应该做邪恶的不可移植的过时的事情,比如触摸我的环境吗?如果没有,那么对于管理环境变量更改有什么好的建议,我需要将其提供给多个子进程?


答案 1

为了在需要为单元测试设置特定环境值的方案中使用,您可能会发现以下 hack 很有用。它将更改整个 JVM 中的环境变量(因此请确保在测试后重置所有更改),但不会更改系统环境。

我发现Edward Campbell和anonymous的两个肮脏黑客的组合效果最好,因为一个在linux下不起作用,另一个在Windows 7下不起作用。因此,为了获得多平台的邪恶黑客,我将它们组合在一起:

protected static void setEnv(Map<String, String> newenv) throws Exception {
  try {
    Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
    Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
    theEnvironmentField.setAccessible(true);
    Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
    env.putAll(newenv);
    Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
    theCaseInsensitiveEnvironmentField.setAccessible(true);
    Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
    cienv.putAll(newenv);
  } catch (NoSuchFieldException e) {
    Class[] classes = Collections.class.getDeclaredClasses();
    Map<String, String> env = System.getenv();
    for(Class cl : classes) {
      if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Object obj = field.get(env);
        Map<String, String> map = (Map<String, String>) obj;
        map.clear();
        map.putAll(newenv);
      }
    }
  }
}

这就像一个魅力。完全归功于这些黑客的两位作者。


答案 2

(这是因为这是Java,因此我不应该做邪恶的不可移植的过时的事情,比如触摸我的环境吗?

我认为你已经击中了头上的钉子。

减轻负担的一种可能方法是分解出一种方法。

void setUpEnvironment(ProcessBuilder builder) {
    Map<String, String> env = builder.environment();
    // blah blah
}

并在启动它们之前通过它传递任何s。ProcessBuilder

另外,您可能已经知道这一点,但是您可以使用相同的.因此,如果您的子流程相同,则无需一遍又一遍地进行此设置。ProcessBuilder


推荐