如何从 Java 设置环境变量?我发现我可以使用 ProcessBuilder
对子进程执行此操作。不过,我有几个子进程要启动,所以我宁愿修改当前进程的环境并让子进程继承它。
有一个System.getenv(String)
用于获取单个环境变量。我还可以使用 System.getenv()
获取完整环境变量集的 Map
。但是,在 Map
上调用 put()
会抛出 UnsupportedOperationException
—— 显然它们意味着环境是只读的。而且,没有 System.setenv()
。
那么,有没有办法在当前运行的进程中设置环境变量呢?如果是这样,怎么办?如果不是,理由是什么? (是不是因为这是 Java,因此我不应该做一些邪恶的、不可移植的过时的事情,比如触摸我的环境?)如果不是,那么有什么好的建议来管理我需要提供给几个人的环境变量更改吗?子流程?
对于需要为单元测试设置特定环境值的场景,您可能会发现以下技巧很有用。它将更改整个 JVM 的环境变量(因此请确保在测试后重置所有更改),但不会更改您的系统环境。
我发现 Edward Campbell 和匿名者的两个肮脏黑客的组合效果最好,因为一个在 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);
}
}
}
}
这就像一个魅力。完全归功于这些黑客的两位作者。
我是一名优秀的程序员,十分优秀!