如何从Java设置环境变量?我看到我可以使用来对子流程执行此操作ProcessBuilder。不过,我有几个子流程要启动,所以我宁愿修改当前流程的环境,并让这些子流程继承它。
有一个System.getenv(String)获取单个环境变量的方法。我还可以使用获取Map完整的环境变量集System.getenv()。但是,调用put()该方法Map将引发UnsupportedOperationException-显然,这意味着该环境是只读的。而且,没有System.setenv()。
System.getenv(String)
System.getenv()
UnsupportedOperationException
System.setenv()
那么,有什么方法可以在当前运行的进程中设置环境变量?如果是这样,怎么办?如果没有,有什么根据?(是因为这是Java,所以我不应该像在触摸我的环境那样做邪恶的,不可移植的过时的事情吗?)如果没有,那么管理环境变量更改的任何好的建议都需要反馈给几个子流程?
(是因为这是Java,所以我不应该像触摸我的环境那样做邪恶的,不可移植的过时的事情吗?)
我认为你已经打中了头。
减轻负担的一种可能方法是排除一种方法
void setUpEnvironment(ProcessBuilder builder) { Map<String, String> env = builder.environment(); // blah blah }
并ProcessBuilder在启动它们之前通过它。
ProcessBuilder
另外,你可能已经知道这一点,但是可以使用相同的命令启动多个进程ProcessBuilder。因此,如果你的子流程相同,则无需一遍又一遍地进行此设置。
对于需要为单元测试设置特定环境值的场景,你可能会发现以下技巧很有用。它会在整个JVM中更改环境变量(因此请确保在测试后重置所有更改),但不会更改你的系统环境。
我发现爱德华·坎贝尔和匿名的两个肮脏黑客的组合效果最好,因为其中一个在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); } } } }