Vic*_*cky 42 java environment-variables
是否可以在运行时从Java应用程序设置环境变量?在Java 1.5 java.lang.System类中有getenv()方法,我只需要一个setenv()方法......
是否可以在java进程本身中修改环境变量; 不在孩子的过程中.
是否有可能通过JNI实现它?那会怎么样?
谢谢.
编辑:好的,让我这样说吧 - 我们可以用Java做以下几点.请回答.
Hemal Pandya回答说:"您可以修改当前和子进程的环境,但不能修改产生此进程的父进程的环境." 你同意吗?
vla*_*adr 35
如果我的直觉是正确的,并且您实际上想要为衍生(分叉)子进程(Runtime.getRuntime().exec()
)的利益修改环境,那么使用ProcessBuilder而不是exec()
.您可以通过ProcessBuilder
实例的environment()方法构建自定义环境.
如果这不是你想要达到的目的,那么请不要理会这个答案.
UPDATE
您的三个更新的具体问题的答案如下:
System.getenv()
同一JVM中返回的值,或两者.setenv
通过JNI 调用它或其特定于平台的等价物.您也可以使用下面第2点中极其复杂的方法,该方法适用于任何进程(前提是您拥有权限.)但是,请注意,在大多数JVM中,此更改可能永远不会反映在返回的值中System.getenv()
,因为环境是通常在java.util.Map
(或等效的)虚拟机启动时缓存.System.java
将用于部署的JVM分发中的源代码),您可以尝试破解实现(通过类加载顺序,反射或检测.例如,对于SUN的v1.6 JVM,环境缓存由未记录的ProcessEnvironment
类(可以修补)管理.gdb
都将暂停非零时间.ProcessBuilder
产生过程.请注意,除了涉及的方法之外,上述所有方法ProcessBuilder
都是脆弱的,容易出错,在不同程度上不可移植,并且在多线程环境中容易出现竞争条件.
回答您的更新问题:
setenv()
或其他什么.你可能不需要这样做,它可能不适用于所有情况.ProcessBuilder
.@Narcoleptic Snowman 的回答让我走上了正确的道路,但是它神秘地不适用于 Oracle JDK 1.8.0_231(他使用次要版本 _144 进行了测试)。即使我能够更新底层 Map(通过System.getenv()
在向 Map 添加新属性之前和之后打印出来进行验证),但在使用System.getenv("property")
.
经过一番调查,我发现这是因为System.getenv()
并System.getenv("property")
最终使用了 的不同静态属性java.lang.ProcessEnvironment
,这些属性在类的static
块中初始化。因此,是否将新属性添加到使用检索的 Map 中并不重要System.getenv()
;这些属性在 使用的其他 Map 中将不可用System.getenv("property")
。
所以我改变了@Narcoleptic Snowman 的答案来处理这种情况,并来到下面的代码。请注意,这仅在您使用System.getenv("property")
;检索属性时才有效;如果您使用,System.getenv().get("property")
那么他的答案就是您所需要的。用法如下:
@SuppressWarnings("unchecked")
private static Map<String, String> getModifiableEnvironment() throws Exception
{
Class<?> pe = Class.forName("java.lang.ProcessEnvironment");
Method getenv = pe.getDeclaredMethod("getenv", String.class);
getenv.setAccessible(true);
Field props = pe.getDeclaredField("theCaseInsensitiveEnvironment");
props.setAccessible(true);
return (Map<String, String>) props.get(null);
}
Run Code Online (Sandbox Code Playgroud)
此方法应按如下方式使用:
getModifiableEnvironment().put("propName", "propValue");
System.getenv("propName"); // this will return "propValue"
Run Code Online (Sandbox Code Playgroud)
您可以在ProcessEnvironment所坚持的基础地图上获得一个句柄,然后放置新的东西并删除所有想要的东西。
这适用于Java 1.8.0_144。无法保证它可以在任何其他Java版本上运行,但是如果您确实需要在运行时更改环境,则可能类似。
private static Map<String,String> getModifiableEnvironment() throws Exception{
Class pe = Class.forName("java.lang.ProcessEnvironment");
Method getenv = pe.getDeclaredMethod("getenv");
getenv.setAccessible(true);
Object unmodifiableEnvironment = getenv.invoke(null);
Class map = Class.forName("java.util.Collections$UnmodifiableMap");
Field m = map.getDeclaredField("m");
m.setAccessible(true);
return (Map) m.get(unmodifiableEnvironment);
}
Run Code Online (Sandbox Code Playgroud)
获取对地图的引用后,只需添加所需的内容,现在就可以使用常规的旧System.getenv(“”)调用来检索它。
我试过了,这在Mac OS的两个OS版本1.8_161中都无法在MAC中工作
我不这么认为,至少不是纯粹用Java,但为什么需要这样做呢?在 Java 中,最好通过 来使用属性System.getProperties()
,您可以对其进行修改。
如果您确实必须这样做,我确信您可以将 Csetenv
函数包装在 JNI 调用中 - 事实上,如果有人已经这样做了,我不会感到惊讶。不过我不知道代码的详细信息。