是否可以在运行时从Java设置环境变量?

时间:2021-05-10 23:08:15

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做以下几点。请回答。

  1. Can we modify the environment of the current process?
  2. 我们可以修改当前流程的环境吗?

  3. Can we modify the environment of the parent process?
  4. 我们可以修改父进程的环境吗?

  5. Can we modify the environment of the child process?
  6. 我们可以修改子进程的环境吗?

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回答说:“您可以修改当前和子进程的环境,但不能修改产生此进程的父进程的环境。”你同意吗?

5 个解决方案

#1


34  

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 ProcessBuilder instead 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 not what you are trying to achieve then kindly disregard this answer.

如果这不是你想要达到的目的,那么请不要理会这个答案。


UPDATE

The answer to your three updated, specific questions is as follows:

您的三个更新的具体问题的答案如下:

  1. 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.
    • 不容易。取决于您是否要更改进程的环境,更改System.getenv()在同一JVM中返回的值,或两者。

    • 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 2 below, 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 by System.getenv(), as the environment is more often than not cached at virtual machine startup in a java.util.Map (or equivalent.)
    • 正如Greg Hewgill所指出的,要改变当前进程的环境,你可以通过JNI调用setenv或其特定于平台的等价物。您也可以使用下面第2点中极其复杂的方法,该方法适用于任何进程(前提是您具有权限。)但是,请注意,在大多数JVM中,此更改可能永远不会反映在System.getenv()返回的值中,因为环境通常是在java.util.Map(或等效的)虚拟机启动时缓存的。

    • 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 undocumented ProcessEnvironment class (which you can patch.)
    • 要更改JVM的缓存环境副本,当使用缓存时(请参阅System.java中的源代码,无论您将使用哪个JVM分发版),您可以尝试破解实现(通过类加载顺序,反射,例如,对于SUN的v1.6 JVM,环境缓存由未记录的ProcessEnvironment类(可以修补)管理。

  2. 我们可以修改当前流程的环境吗?不容易。取决于您是否要更改进程的环境,更改System.getenv()在同一JVM中返回的值,或两者。正如Greg Hewgill所指出的,要改变当前进程的环境,你可以通过JNI调用setenv或其特定于平台的等价物。您也可以使用下面第2点中极其复杂的方法,该方法适用于任何进程(前提是您具有权限。)但是,请注意,在大多数JVM中,此更改可能永远不会反映在System.getenv()返回的值中,因为环境通常在java.util.Map(或等效物)中的虚拟机启动时缓存。要在使用缓存时更改JVM的缓存环境副本(请参阅System.java中的源代码)在您将用于部署的任何JVM分发中,您可以尝试破解实现(通过类加载顺序,反射或检测。)例如,在SUN的v1.6 JVM的情况下,环境缓存由未记录的ProcessEnvironment类(您可以修补它。)

  3. 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:动态添加/编辑远程进程的环境变量* nix:有没有办法更改另一个进程的环境变量? - 这是一个性能杀手,因为gdb检测的任何进程都将暂停非零时间。

  4. 我们可以修改父进程的环境吗?非常困难,非常便携。如果您绝对必须这样做,那么您可以使用非常具体的黑客攻击:Windows:动态添加/编辑远程进程的环境变量* nix:有没有办法更改另一个进程的环境变量? - 这是一个性能杀手,因为gdb检测的任何进程都将暂停非零时间。

  5. Can we modify the environment of the child process?
    • Yes, through ProcessBuilder when spawning the process.
    • 是的,在产生流程时通过ProcessBuilder。

    • If the process has already been spawned when the environment alteration is required, you need method 2 above (or some equally convoluted method, such as code-injection at spawn time, ulteriorly controlled through e.g. socket by the parent process.)
    • 如果在需要进行环境更改时已经生成了该进程,则需要上面的方法2(或者某些同样复杂的方法,例如在生成时进行代码注入,通过父进程对插槽进行进一步控制)。

  6. 我们可以修改子进程的环境吗?是的,在产生流程时通过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的方法之外,上述所有方法都很脆弱,容易出错,在不同程度上不可移植,并且在多线程环境中容易出现竞争条件。

#2


5  

In response to your updated question:

回答您的最新问题:

  1. Can we modify the environment of the current process?
    Yes, if you use JNI to call setenv() or something. You probably don't need to do this though, and it may not work in all situations.
  2. 我们可以修改当前流程的环境吗?是的,如果您使用JNI来调用setenv()或其他东西。你可能不需要这样做,它可能不适用于所有情况。

  3. Can we modify the environment of the parent process?
    No.
  4. 我们可以修改父进程的环境吗?没有。

  5. Can we modify the environment of the child process?
    Yes, using ProcessBuilder.
  6. 我们可以修改子进程的环境吗?是的,使用ProcessBuilder。

#3


4  

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中工作,不能在Windows java版本1.8_161中工作

#4


1  

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.

如果你真的必须,我相信你可以在JNI调用中包装C setenv函数 - 事实上,如果有人已经这样做,我也不会感到惊讶。但是,我不知道代码的细节。

#5


0  

You can modify the environment of current and child processes but not of the parent process that spawned this process.

您可以修改当前和子进程的环境,但不能修改生成此进程的父进程的环境。

#1


34  

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 ProcessBuilder instead 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 not what you are trying to achieve then kindly disregard this answer.

如果这不是你想要达到的目的,那么请不要理会这个答案。


UPDATE

The answer to your three updated, specific questions is as follows:

您的三个更新的具体问题的答案如下:

  1. 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.
    • 不容易。取决于您是否要更改进程的环境,更改System.getenv()在同一JVM中返回的值,或两者。

    • 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 2 below, 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 by System.getenv(), as the environment is more often than not cached at virtual machine startup in a java.util.Map (or equivalent.)
    • 正如Greg Hewgill所指出的,要改变当前进程的环境,你可以通过JNI调用setenv或其特定于平台的等价物。您也可以使用下面第2点中极其复杂的方法,该方法适用于任何进程(前提是您具有权限。)但是,请注意,在大多数JVM中,此更改可能永远不会反映在System.getenv()返回的值中,因为环境通常是在java.util.Map(或等效的)虚拟机启动时缓存的。

    • 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 undocumented ProcessEnvironment class (which you can patch.)
    • 要更改JVM的缓存环境副本,当使用缓存时(请参阅System.java中的源代码,无论您将使用哪个JVM分发版),您可以尝试破解实现(通过类加载顺序,反射,例如,对于SUN的v1.6 JVM,环境缓存由未记录的ProcessEnvironment类(可以修补)管理。

  2. 我们可以修改当前流程的环境吗?不容易。取决于您是否要更改进程的环境,更改System.getenv()在同一JVM中返回的值,或两者。正如Greg Hewgill所指出的,要改变当前进程的环境,你可以通过JNI调用setenv或其特定于平台的等价物。您也可以使用下面第2点中极其复杂的方法,该方法适用于任何进程(前提是您具有权限。)但是,请注意,在大多数JVM中,此更改可能永远不会反映在System.getenv()返回的值中,因为环境通常在java.util.Map(或等效物)中的虚拟机启动时缓存。要在使用缓存时更改JVM的缓存环境副本(请参阅System.java中的源代码)在您将用于部署的任何JVM分发中,您可以尝试破解实现(通过类加载顺序,反射或检测。)例如,在SUN的v1.6 JVM的情况下,环境缓存由未记录的ProcessEnvironment类(您可以修补它。)

  3. 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:动态添加/编辑远程进程的环境变量* nix:有没有办法更改另一个进程的环境变量? - 这是一个性能杀手,因为gdb检测的任何进程都将暂停非零时间。

  4. 我们可以修改父进程的环境吗?非常困难,非常便携。如果您绝对必须这样做,那么您可以使用非常具体的黑客攻击:Windows:动态添加/编辑远程进程的环境变量* nix:有没有办法更改另一个进程的环境变量? - 这是一个性能杀手,因为gdb检测的任何进程都将暂停非零时间。

  5. Can we modify the environment of the child process?
    • Yes, through ProcessBuilder when spawning the process.
    • 是的,在产生流程时通过ProcessBuilder。

    • If the process has already been spawned when the environment alteration is required, you need method 2 above (or some equally convoluted method, such as code-injection at spawn time, ulteriorly controlled through e.g. socket by the parent process.)
    • 如果在需要进行环境更改时已经生成了该进程,则需要上面的方法2(或者某些同样复杂的方法,例如在生成时进行代码注入,通过父进程对插槽进行进一步控制)。

  6. 我们可以修改子进程的环境吗?是的,在产生流程时通过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的方法之外,上述所有方法都很脆弱,容易出错,在不同程度上不可移植,并且在多线程环境中容易出现竞争条件。

#2


5  

In response to your updated question:

回答您的最新问题:

  1. Can we modify the environment of the current process?
    Yes, if you use JNI to call setenv() or something. You probably don't need to do this though, and it may not work in all situations.
  2. 我们可以修改当前流程的环境吗?是的,如果您使用JNI来调用setenv()或其他东西。你可能不需要这样做,它可能不适用于所有情况。

  3. Can we modify the environment of the parent process?
    No.
  4. 我们可以修改父进程的环境吗?没有。

  5. Can we modify the environment of the child process?
    Yes, using ProcessBuilder.
  6. 我们可以修改子进程的环境吗?是的,使用ProcessBuilder。

#3


4  

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中工作,不能在Windows java版本1.8_161中工作

#4


1  

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.

如果你真的必须,我相信你可以在JNI调用中包装C setenv函数 - 事实上,如果有人已经这样做,我也不会感到惊讶。但是,我不知道代码的细节。

#5


0  

You can modify the environment of current and child processes but not of the parent process that spawned this process.

您可以修改当前和子进程的环境,但不能修改生成此进程的父进程的环境。