一、概述
如何在Java中设置环境变量?我看到我可以使用ProcessBuilder来对子流程执行此操作。不过,我有几个子流程要启动,因此我宁愿修改当前流程的环境,并让这些子流程继承它。
有一个System.getenv(String)用于获取单个环境变量。我还可以使用System.getenv()获取完整的环境变量集Map。但是,调用put()方法将引发UnsupportedOperationException-显然,这意味着该环境是只读的。而且,没有System.setenv()。
那么,有什么方法可以在当前运行的进程中设置环境变量?
二、详解
对于需要为单元测试设置特定环境值的场景,您可能会发现以下技巧很有用。它会在整个JVM中更改环境变量(因此请确保在测试后重置所有更改),但不会更改您的系统环境。
我发现两个的组合效果最好,因为其中一个在Linux下不起作用,一个在Windows 7下不起作用。因此,将它们结合在一起:
protected static void setEnv(Map newenv) throws Exception {
try {
Class> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map env = (Map) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map cienv = (Map) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
} catch (NoSuchFieldException e) {
Class[] classes = Collections.class.getDeclaredClasses();
Map 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 map = (Map) obj;
map.clear();
map.putAll(newenv);
}
}
}
}
这些代码完全归功于两位骇客作者。