Можно ли установить переменную среды во время выполнения из Java? - PullRequest
39 голосов
/ 24 февраля 2009

Можно ли установить переменную среды во время выполнения с Java приложение? В Java 1.5 java.lang.System класс есть метод getenv (), я бы нужен только метод setenv () ...

Возможно ли изменить переменные окружения в самом java-процессе; не в дочернем процессе.

Возможно ли достичь этого через JNI? И как это будет работать?

Спасибо.

EDIT: Хорошо, позвольте мне сказать это следующим образом - Можем ли мы сделать следующее с Java. Пожалуйста, ответьте.

  1. Можем ли мы изменить среду текущего процесса?
  2. Можем ли мы изменить среду родительского процесса?
  3. Можем ли мы изменить среду дочернего процесса?

Хемаль Пандья ответил, что «Вы можете изменять среду текущих и дочерних процессов, но не родительского процесса, который породил этот процесс». Вы согласны с этим?

Ответы [ 5 ]

34 голосов
/ 24 февраля 2009

Если моя интуиция верна , и вы действительно хотите изменить среду в интересах порожденного (разветвленного) подпроцесса (Runtime.getRuntime().exec()), тогда используйте ProcessBuilder вместо exec(). Вы можете создать пользовательскую среду с помощью метода environment () вашего экземпляра ProcessBuilder.

Если это , а не , что вы пытаетесь достичь, тогда, пожалуйста, не обращайте внимания на этот ответ.


UPDATE

Ответ на ваши три обновленных конкретных вопроса следующий:

  1. Можем ли мы изменить среду текущего процесса?
    • Не легко . Зависит от того, хотите ли вы изменить среду процесса, изменить значения, возвращаемые System.getenv() в той же JVM, или обеими.
    • Как отметил Грег Хьюгилл, чтобы изменить среду текущего процесса, вы можете позвонить setenv или его специфичный для платформы эквивалент через JNI. Вы также можете использовать чрезвычайно запутанный метод из точка 2 ниже, который работает для любого процесса (при условии, что у вас есть разрешения.) Однако учтите, что в большинстве JVM это изменение может никогда не отразиться на возвращаемых значениях. на System.getenv(), так как среда чаще всего кэшируется при запуске виртуальной машины в java.util.Map (или эквивалентном).
    • Чтобы изменить кешированную копию среды JVM, когда используется кеш (см. Исходный код в System.java в любом дистрибутиве JVM, который вы будете использовать для развертывания), вы можете попробовать взломать реализацию (через порядок загрузки классов , отражение или инструментарий .) Например, в случае JVM SUN v1.6 кэш среды управляется недокументированным классом ProcessEnvironment (который можно исправить). )
  2. Можем ли мы изменить среду родительского процесса?
  3. Можем ли мы изменить среду дочернего процесса?
    • Да , до ProcessBuilder при порождении процесса.
    • Если процесс уже был порожден, когда требуется изменение среды, вам нужен метод 2 выше (или какой-то такой же извилистый метод, как, например, внедрение кода во время появления, которое внешне контролируется, например, через сокет с помощью родительский процесс.)

Обратите внимание, что все вышеперечисленные методы, за исключением одного, включающего ProcessBuilder, являются хрупкими, подверженными ошибкам, непереносимыми в различной степени и склонными к гоночным условиям в многопоточных средах.

6 голосов
/ 24 февраля 2009

В ответ на ваш обновленный вопрос:

  1. Можем ли мы изменить среду текущего процесса?
    Да , если вы используете JNI для вызова setenv() или что-то еще. Возможно, вам не нужно этого делать, и это может не сработать во всех ситуациях.
  2. Можем ли мы изменить среду родительского процесса?
    нет Нет .
  3. Можем ли мы изменить среду дочернего процесса?
    Да , используя ProcessBuilder.
5 голосов
/ 27 сентября 2017

Вы можете получить указатель на базовую карту, которую удерживает 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);
}

После того, как вы получите ссылку на карту, просто добавьте все, что вы хотите, и теперь вы можете получить ее, используя обычный старый вызов System.getenv ("").

Я попробовал это, он работает в MAC, не работает в Windows в обеих версиях ОС Java 1.8_161

1 голос
/ 24 февраля 2009

Я так не думаю, по крайней мере, не только на Java, но зачем вам это делать? В Java предпочтительно использовать свойства через System.getProperties(), которые вы можете изменять.

Если вы действительно должны, я уверен, что вы могли бы обернуть функцию C setenv в вызов JNI - на самом деле, я не удивлюсь, если кто-то уже сделал это. Я не знаю деталей кода, хотя.

0 голосов
/ 24 февраля 2009

Вы можете изменить среду текущих и дочерних процессов, но не родительского процесса, который породил этот процесс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...