如何从 Java 设置环境变量?

新手上路,请多包涵

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

有一个 System.getenv(String) 用于获取单个环境变量。我还可以使用 Map 获得完整的环境变量集 System.getenv() 。但是,调用 put() Map 抛出 UnsupportedOperationException 显然它们意味着环境是只读的。而且,没有 System.setenv()

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

原文由 skiphoppy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 841
2 个回答

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

我想你已经击中要害了。

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

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

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

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

原文由 Michael Myers 发布,翻译遵循 CC BY-SA 2.5 许可协议

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

我发现将 Edward Campbell 和 anonymous 的两个肮脏 hack 结合起来效果最好,因为一个在 linux 下不起作用,另一个在 windows 7 下不起作用。所以为了得到一个多平台的邪恶 hack,我结合了它们:

 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);
      }
    }
  }
}

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

原文由 pushy 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题