是否可以在运行时从 Java 设置环境变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/580085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to set an environment variable at runtime from Java?
提问by Vicky
Is it possible to set an environment variable at runtime from a Java application? In Java 1.5 java.lang.System class there is the getenv() method, I would only need a setenv() method...
是否可以在运行时从 Java 应用程序设置环境变量?在 Java 1.5 java.lang.System 类中有 getenv() 方法,我只需要一个 setenv() 方法...
Is it possible to modify the environment variables in the java process itself; not in the child process.
是否可以修改java进程本身的环境变量;不在子进程中。
Is it possible to achieve it through JNI? And how would that work?
是否可以通过 JNI 实现?这将如何运作?
Thanks.
谢谢。
EDIT: Ok let me put it this way - Can we do the following with Java. Please answer.
编辑:好的,让我这样说 - 我们可以用 Java 做以下事情吗?请回答。
- Can we modify the environment of the current process?
- Can we modify the environment of the parent process?
- Can we modify the environment of the child process?
- 我们可以修改当前进程的环境吗?
- 可以修改父进程的环境吗?
- 我们可以修改子进程的环境吗?
Hemal Pandya has answered that "You can modify the environment of current and child processes but not of the parent process that spawned this process." Do you agree with this ?
Hemal Pandya 回答说:“您可以修改当前和子进程的环境,但不能修改产生此进程的父进程的环境。” 你同意吗?
回答by David Z
I don't think so, at least not purely in Java, but why do you need to do this? In Java it's preferable to use properties via System.getProperties()
, which you can modify.
我不这么认为,至少不是纯粹用 Java 写的,但是你为什么需要这样做呢?在 Java 中,最好通过 使用属性System.getProperties()
,您可以修改它。
If you really must, I'm sure you could wrap the C setenv
function in a JNI call - in fact, I wouldn't be surprised if someone has done so already. I don't know the details of the code, though.
如果您真的必须这样做,我相信您可以将 Csetenv
函数包装在 JNI 调用中 - 事实上,如果有人已经这样做了,我不会感到惊讶。不过,我不知道代码的详细信息。
回答by vladr
If my intuition is correct, and you actually want to modify the environment for the benefit of a spawned (forked) sub-process (Runtime.getRuntime().exec()
), then use ProcessBuilderinstead of exec()
. You can build a custom environment via your ProcessBuilder
instance's environment()method.
如果我的直觉是正确的,并且您实际上想要修改环境以有利于生成的(分叉的)子进程 ( Runtime.getRuntime().exec()
),那么使用ProcessBuilder而不是exec()
. 您可以通过ProcessBuilder
实例的environment()方法构建自定义环境。
If this is notwhat you are trying to achieve then kindly disregard this answer.
如果这不是您想要实现的目标,请忽略此答案。
UPDATE
更新
The answer to your three updated, specific questions is as follows:
您三个更新的具体问题的答案如下:
- Can we modify the environment of the current process?
- Not easily. Depends whether you want to change the process' environment, to change the value(s) returned by
System.getenv()
in the same JVM, or both. - As Greg Hewgill pointed out, to change the current process' environment you can call
setenv
or its platform-specific equivalent via JNI. You may also employ the extremely convoluted method from point 2below, which works for any process (provided you have the permissions.) However, be aware that in most JVMs this change might never be reflected in the values returned bySystem.getenv()
, as the environment is more often than not cached at virtual machine startup in ajava.util.Map
(or equivalent.) - To change the JVM's cached copy of the environment, when a cache is used (see the source code in
System.java
in whichever JVM distribution you will be using to deploy), you may try hacking the implementation (via class loading order, reflection, or instrumentation.) In the case of SUN's v1.6 JVM, for example, the environment cache is managed by the undocumentedProcessEnvironment
class (which you can patch.)
- Not easily. Depends whether you want to change the process' environment, to change the value(s) returned by
- Can we modify the environment of the parent process?
- Extremely difficult, and highly non-portable. If you absolutely and imperatively have to, there are very specific hacks that you can employ:
- Windows: Dynamically Add/Edit Environment variables of Remote process
- *nix: Is there a way to change another process's environment variables?-- this is a performance killer, as any process instrumented by
gdb
will be suspended for a non-zero amount of time.
- Extremely difficult, and highly non-portable. If you absolutely and imperatively have to, there are very specific hacks that you can employ:
- Can we modify the environment of the child process?
- Yes, through
ProcessBuilder
when spawning the process. - If the process has already been spawned when the environment alteration is required, you need method 2above (or some equally convoluted method, such as code-injection at spawn time, ulteriorly controlled through e.g. socket by the parent process.)
- Yes, through
- 我们可以修改当前进程的环境吗?
- 不容易。取决于您是要更改进程的环境,还是要更改
System.getenv()
同一 JVM 中返回的值,还是两者兼而有之。 - 正如 Greg Hewgill 指出的那样,要更改当前进程的环境,您可以
setenv
通过 JNI调用或其特定于平台的等效项。您还可以使用下面第 2 点中极其复杂的方法,该方法适用于任何进程(前提是您具有权限)。但是,请注意,在大多数 JVM 中,此更改可能永远不会反映在 返回的值中System.getenv()
,因为环境是通常在虚拟机启动时缓存在java.util.Map
(或等效的)中。 - 要更改环境的 JVM 缓存副本,当使用缓存时(请参阅
System.java
您将用于部署的任何 JVM 发行版中的源代码),您可以尝试破解实现(通过类加载顺序、反射或检测)。 ) 例如,在 SUN 的 v1.6 JVM 的情况下,环境缓存由未记录的ProcessEnvironment
类(您可以修补)管理。
- 不容易。取决于您是要更改进程的环境,还是要更改
- 可以修改父进程的环境吗?
- 极其困难,并且高度不可携带。如果您绝对且必须这样做,您可以使用一些非常具体的技巧:
- Windows:动态添加/编辑远程进程的环境变量
- *nix:有没有办法改变另一个进程的环境变量?-- 这是一个性能杀手,因为任何被检测的进程
gdb
都将暂停非零时间。
- 极其困难,并且高度不可携带。如果您绝对且必须这样做,您可以使用一些非常具体的技巧:
- 我们可以修改子进程的环境吗?
- 是的,通过
ProcessBuilder
产生进程时。 - 如果在需要更改环境时已经生成了进程,则您需要上面的方法 2(或一些同样复杂的方法,例如生成时的代码注入,由父进程通过例如套接字进行最终控制。)
- 是的,通过
Note that all methods above, except for the one involving ProcessBuilder
, are brittle, error prone, non-portable to various degrees, and prone to race conditions in multi-threaded environments.
请注意,除了涉及 的方法之外,上述所有方法ProcessBuilder
都很脆弱,容易出错,在不同程度上不可移植,并且在多线程环境中容易出现竞争条件。
回答by Miserable Variable
You can modify the environment of current and child processes but not of the parent process that spawned this process.
您可以修改当前和子进程的环境,但不能修改产生此进程的父进程的环境。
回答by Greg Hewgill
In response to your updated question:
针对您更新的问题:
- Can we modify the environment of the current process?
Yes, if you use JNI to callsetenv()
or something. You probably don't need to do this though, and it may not work in all situations. - Can we modify the environment of the parent process?
No. - Can we modify the environment of the child process?
Yes, usingProcessBuilder
.
- 我们可以修改当前进程的环境吗?
是的,如果你使用 JNI 来调用setenv()
什么的。不过,您可能不需要这样做,它可能不适用于所有情况。 - 可以修改父进程的环境吗?
没有。 - 我们可以修改子进程的环境吗?
是的,使用ProcessBuilder
.
回答by Narcoleptic Snowman
You can get a handle on the underlying map that ProcessEnvironment is holding on to, and then put new stuff and remove stuff all you want.
您可以获取 ProcessEnvironment 所持有的底层映射的句柄,然后放置新内容并删除所有您想要的内容。
This works on java 1.8.0_144. Can't guarantee it works on any other version of java, but it's probably similar if you really need to change the environment at run time.
这适用于 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);
}
After you get the reference to the map, just add whatever you want and you can now retrieve it using the regular old System.getenv("") call.
获得对地图的引用后,只需添加您想要的任何内容,现在您可以使用常规的旧 System.getenv("") 调用检索它。
I tried this its working in MAC not working in Windows in both os java version 1.8_161
我试过这个它在 MAC 中工作在两个操作系统 java 版本 1.8_161 中都不能在 Windows 中工作