Подтвердить что ты не робот

Можно ли установить переменную среды во время выполнения из Java?

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

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

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

Спасибо.

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

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

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

4b9b3361

Ответ 1

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

Если это не то, чего вы пытаетесь достичь, тогда любезно проигнорируйте этот ответ.


UPDATE

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

Вы можете получить ручку на базовой карте, к которой относится 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("").

Ответ 5

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