Java에서 환경변수를 설정하려면 어떻게 해야 합니까?
Java에서 환경변수를 설정하려면 어떻게 해야 합니까?를 사용하여 서브프로세스에 대해 이 작업을 수행할 수 있습니다.그러나 시작해야 할 하위 프로세스가 몇 개 있기 때문에 현재 프로세스의 환경을 수정하고 하위 프로세스가 이 프로세스를 상속하도록 하겠습니다.
게 요.System.getenv(String)
이치 또 '아까보다'도 수 있어요.Map
중 '환경변수'가 '환경변수'로 되어 있다.System.getenv()
, ★★★★★★★★★★★★★★★★★★★★★★★★.put()
점에 있어서Map
UnsupportedOperationException
읽기 전용의 환경을 의미하는 것 같습니다.그리고 없어요.System.setenv()
.
그렇다면 현재 진행 중인 프로세스에서 환경변수를 설정할 수 있는 방법이 있을까요?만약 그렇다면, 어떻게?그렇지 않다면, 그 근거는 무엇입니까?(Java이기 때문에 환경에 손을 대는 등, 휴대할 수 없는 악랄한 구태의연한 행동을 해서는 안 되는 것일까요?그렇지 않은 경우 환경변수 변경을 관리하기 위해 몇 가지 서브프로세스에 제공해야 할 좋은 제안이 있습니까?
장치 테스트를 위해 특정 환경 값을 설정해야 하는 시나리오에서 사용할 경우 다음과 같은 해킹이 유용할 수 있습니다.JVM 전체에서 환경변수가 변경되지만(테스트 후 변경사항은 반드시 리셋하십시오) 시스템 환경은 변경되지 않습니다.
Edward Campbell의 두 개의 더러운 해킹과 익명 해킹의 조합이 가장 적합하다는 것을 알게 되었습니다.그 중 하나는 Linux에서 동작하지 않고 하나는 Windows 7에서 동작하지 않기 때문입니다.그래서 멀티플랫폼의 사악한 해킹을 얻기 위해 그것들을 결합했습니다.
protected static void setEnv(Map<String, String> newenv) throws Exception {
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
} catch (NoSuchFieldException e) {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for(Class cl : classes) {
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
}
}
이거 참 잘 먹히는군해킹의 저자인 두 명의 공로를 인정합니다
(Java이기 때문에 환경에 손을 대는 등, 휴대할 수 없는 악랄한 구태의연한 행동을 해서는 안 되는 것일까요?
정곡을 찌른 것 같아요.
부담을 덜 수 있는 가능한 방법은 한 가지 방법을 고려하는 것입니다.
void setUpEnvironment(ProcessBuilder builder) {
Map<String, String> env = builder.environment();
// blah blah
}
것이든 통과시키다ProcessBuilder
를 실행해 주세요.
, 번 할 수 .ProcessBuilder
따라서 서브프로세스가 동일할 경우 이 셋업을 반복할 필요가 없습니다.
public static void set(Map<String, String> newenv) throws Exception {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for(Class cl : classes) {
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
}
또는 joshwolfe의 제안에 따라 단일 변수를 추가/업데이트하고 루프를 제거합니다.
@SuppressWarnings({ "unchecked" })
public static void updateEnv(String name, String val) throws ReflectiveOperationException {
Map<String, String> env = System.getenv();
Field field = env.getClass().getDeclaredField("m");
field.setAccessible(true);
((Map<String, String>) field.get(env)).put(name, val);
}
Linux/MacOS만
단일 환경 변수 설정(Edward Campbell의 답변에 기반):
public static void setEnv(String key, String value) {
try {
Map<String, String> env = System.getenv();
Class<?> cl = env.getClass();
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Map<String, String> writableEnv = (Map<String, String>) field.get(env);
writableEnv.put(key, value);
} catch (Exception e) {
throw new IllegalStateException("Failed to set environment variable", e);
}
}
사용방법:
먼저 메서드를 원하는 클래스(예: SystemUtil)에 넣습니다.그런 다음 정적으로 호출합니다.
SystemUtil.setEnv("SHELL", "/bin/bash");
「 」에 System.getenv("SHELL")
이 일이 끝나면"/bin/bash"
syslog.syslog.syslog.
// this is a dirty hack - but should be ok for a unittest.
private void setNewEnvironmentHack(Map<String, String> newenv) throws Exception
{
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.clear();
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.clear();
cienv.putAll(newenv);
}
안드로이드에서 인터페이스는 Libcore.os를 통해 숨겨진 API로 노출됩니다.
Libcore.os.setenv("VAR", "value", bOverwrite);
Libcore.os.getenv("VAR"));
Libcore 클래스와 인터페이스 OS는 퍼블릭입니다.클래스 선언만 누락되어 링커에 표시되어야 합니다.응용 프로그램에 클래스를 추가할 필요는 없지만 포함된 경우에도 문제가 없습니다.
package libcore.io;
public final class Libcore {
private Libcore() { }
public static Os os;
}
package libcore.io;
public interface Os {
public String getenv(String name);
public void setenv(String name, String value, boolean overwrite) throws ErrnoException;
}
이는 @paul-blair가 Java로 변환한 답변의 조합입니다.이 답변에는 paul blair가 지적한 청소와 @Edward Campbell과 anonymous로 구성된 @pushy의 코드 안에 있었던 것으로 보이는 오류가 포함되어 있습니다.
나는 이 코드가 얼마나 테스트에만 사용되어야 하는지 강조할 수 없고 매우 해킹적이다.그러나 테스트에서 환경 설정이 필요한 경우에는 이것이 바로 제가 필요로 했던 것입니다.
이것은, 다음의 Windows 로 동작하는 양쪽 모두에서 코드가 동작할 수 있도록, 약간의 조작도 포함하고 있습니다.
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
센토스는 물론
openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)
구현:
/**
* Sets an environment variable FOR THE CURRENT RUN OF THE JVM
* Does not actually modify the system's environment variables,
* but rather only the copy of the variables that java has taken,
* and hence should only be used for testing purposes!
* @param key The Name of the variable to set
* @param value The value of the variable to set
*/
@SuppressWarnings("unchecked")
public static <K,V> void setenv(final String key, final String value) {
try {
/// we obtain the actual environment
final Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
final Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
final boolean environmentAccessibility = theEnvironmentField.isAccessible();
theEnvironmentField.setAccessible(true);
final Map<K,V> env = (Map<K, V>) theEnvironmentField.get(null);
if (SystemUtils.IS_OS_WINDOWS) {
// This is all that is needed on windows running java jdk 1.8.0_92
if (value == null) {
env.remove(key);
} else {
env.put((K) key, (V) value);
}
} else {
// This is triggered to work on openjdk 1.8.0_91
// The ProcessEnvironment$Variable is the key of the map
final Class<K> variableClass = (Class<K>) Class.forName("java.lang.ProcessEnvironment$Variable");
final Method convertToVariable = variableClass.getMethod("valueOf", String.class);
final boolean conversionVariableAccessibility = convertToVariable.isAccessible();
convertToVariable.setAccessible(true);
// The ProcessEnvironment$Value is the value fo the map
final Class<V> valueClass = (Class<V>) Class.forName("java.lang.ProcessEnvironment$Value");
final Method convertToValue = valueClass.getMethod("valueOf", String.class);
final boolean conversionValueAccessibility = convertToValue.isAccessible();
convertToValue.setAccessible(true);
if (value == null) {
env.remove(convertToVariable.invoke(null, key));
} else {
// we place the new value inside the map after conversion so as to
// avoid class cast exceptions when rerunning this code
env.put((K) convertToVariable.invoke(null, key), (V) convertToValue.invoke(null, value));
// reset accessibility to what they were
convertToValue.setAccessible(conversionValueAccessibility);
convertToVariable.setAccessible(conversionVariableAccessibility);
}
}
// reset environment accessibility
theEnvironmentField.setAccessible(environmentAccessibility);
// we apply the same to the case insensitive environment
final Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
final boolean insensitiveAccessibility = theCaseInsensitiveEnvironmentField.isAccessible();
theCaseInsensitiveEnvironmentField.setAccessible(true);
// Not entirely sure if this needs to be casted to ProcessEnvironment$Variable and $Value as well
final Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
if (value == null) {
// remove if null
cienv.remove(key);
} else {
cienv.put(key, value);
}
theCaseInsensitiveEnvironmentField.setAccessible(insensitiveAccessibility);
} catch (final ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">", e);
} catch (final NoSuchFieldException e) {
// we could not find theEnvironment
final Map<String, String> env = System.getenv();
Stream.of(Collections.class.getDeclaredClasses())
// obtain the declared classes of type $UnmodifiableMap
.filter(c1 -> "java.util.Collections$UnmodifiableMap".equals(c1.getName()))
.map(c1 -> {
try {
return c1.getDeclaredField("m");
} catch (final NoSuchFieldException e1) {
throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+"> when locating in-class memory map of environment", e1);
}
})
.forEach(field -> {
try {
final boolean fieldAccessibility = field.isAccessible();
field.setAccessible(true);
// we obtain the environment
final Map<String, String> map = (Map<String, String>) field.get(env);
if (value == null) {
// remove if null
map.remove(key);
} else {
map.put(key, value);
}
// reset accessibility
field.setAccessible(fieldAccessibility);
} catch (final ConcurrentModificationException e1) {
// This may happen if we keep backups of the environment before calling this method
// as the map that we kept as a backup may be picked up inside this block.
// So we simply skip this attempt and continue adjusting the other maps
// To avoid this one should always keep individual keys/value backups not the entire map
LOGGER.info("Attempted to modify source map: "+field.getDeclaringClass()+"#"+field.getName(), e1);
} catch (final IllegalAccessException e1) {
throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">. Unable to access field!", e1);
}
});
}
LOGGER.info("Set environment variable <"+key+"> to <"+value+">. Sanity Check: "+System.getenv(key));
}
@pushy/@anonymous/@Edward Campbell입니다. 【Android】【Java】【Java】【Java】【Java】【안드로이드】안드로이드는 '안드로이드'가 없다.java.lang.ProcessEnvironment
하지만에서는 JNI 을 POSIX로 하면 .setenv()
:
C/JNI의 경우:
JNIEXPORT jint JNICALL Java_com_example_posixtest_Posix_setenv
(JNIEnv* env, jclass clazz, jstring key, jstring value, jboolean overwrite)
{
char* k = (char *) (*env)->GetStringUTFChars(env, key, NULL);
char* v = (char *) (*env)->GetStringUTFChars(env, value, NULL);
int err = setenv(k, v, overwrite);
(*env)->ReleaseStringUTFChars(env, key, k);
(*env)->ReleaseStringUTFChars(env, value, v);
return err;
}
자바어:
public class Posix {
public static native int setenv(String key, String value, boolean overwrite);
private void runTest() {
Posix.setenv("LD_LIBRARY_PATH", "foo", true);
}
}
이 스레드를 발견한 대부분의 사람들과 마찬가지로 저도 몇 가지 유닛 테스트를 작성 중이었고 테스트를 실행하기 위한 올바른 조건을 설정하기 위해 환경 변수를 수정해야 했습니다.그러나 가장 많이 투표된 답변에는 몇 가지 문제가 있거나 매우 복잡하거나 둘 다 있다는 것을 알게 되었습니다.이것이 다른 사람들이 더 빨리 해결책을 찾는 데 도움이 되기를 바랍니다.
우선, @Hubert Greskowiak의 솔루션이 가장 간단하다는 것을 알게 되었고, 나에게도 효과가 있었습니다.내가 먼저 거기에 갔더라면 좋았을 텐데.@Edward Campbell의 답변에 근거하고 있지만, 복잡한 루프 검색은 없습니다.
그러나 저는 가장 많은 표를 얻은 @pushy의 솔루션으로 시작했습니다.@anonymous와 @Edward Campbell의 조합입니다.@pushy는 Linux 환경과 Windows 환경 모두에 대응하려면 두 가지 접근 방식이 모두 필요하다고 주장합니다.OS X에서 실행 중인데 둘 다 동작합니다(@anonymous 접근 방식의 문제가 해결되면).다른 사람들이 지적했듯이, 이 솔루션은 대부분의 경우 작동하지만 전부는 아닙니다.
혼란의 원인은 @anonymous의 '환경' 필드에서 작동하는 솔루션이 원인이라고 생각합니다.Process Environment 구조의 정의를 보면, 「The Environment」는 맵< String, String >이 아니라 맵< Variable, Value >입니다.맵을 클리어하면 정상적으로 동작하지만 putAll 조작에 의해 맵< String, String >이 재구축됩니다.이것에 의해, Map< Variable, Value >가 예상되는 통상의 API 를 사용해 데이터 구조상에서 후속 조작을 실시할 때, 문제가 발생할 가능성이 있습니다.또, 개개의 요소에의 액세스/삭제도 문제가 됩니다.해결책은 '수정할 수 없는 환경'을 통해 '환경'에 간접적으로 액세스하는 것입니다.단, UnmodifyMap 타입이므로 UnmodifyMap 타입의 개인 변수 'm'을 통해 접근해야 합니다.아래 코드의 getModifyEnvironmentMap2를 참조하십시오.
제 경우 테스트에 사용할 환경 변수 중 일부를 제거해야 했습니다(다른 변수는 변경되지 않아야 합니다.그리고 테스트 후 환경변수를 이전 상태로 복원하고 싶었습니다.아래의 루틴은 그것을 바로 할 수 있게 합니다.OS X에서 두 버전의 getModifyEnvironmentMap을 테스트했는데 둘 다 동일하게 동작합니다.이 스레드의 코멘트에 근거하고 있습니다만, 환경에 따라서는 한쪽이 다른 쪽보다 좋은 선택이 될 수 있습니다.
주의: "The Case Insensitive Environment Field"는 Windows 고유의 것으로 보여 테스트 방법이 없었기 때문에 "Case Insensitive Environment Field"에 대한 액세스는 포함하지 않았습니다.단, 직접 추가해야 합니다.
private Map<String, String> getModifiableEnvironmentMap() {
try {
Map<String,String> unmodifiableEnv = System.getenv();
Class<?> cl = unmodifiableEnv.getClass();
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Map<String,String> modifiableEnv = (Map<String,String>) field.get(unmodifiableEnv);
return modifiableEnv;
} catch(Exception e) {
throw new RuntimeException("Unable to access writable environment variable map.");
}
}
private Map<String, String> getModifiableEnvironmentMap2() {
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theUnmodifiableEnvironmentField = processEnvironmentClass.getDeclaredField("theUnmodifiableEnvironment");
theUnmodifiableEnvironmentField.setAccessible(true);
Map<String,String> theUnmodifiableEnvironment = (Map<String,String>)theUnmodifiableEnvironmentField.get(null);
Class<?> theUnmodifiableEnvironmentClass = theUnmodifiableEnvironment.getClass();
Field theModifiableEnvField = theUnmodifiableEnvironmentClass.getDeclaredField("m");
theModifiableEnvField.setAccessible(true);
Map<String,String> modifiableEnv = (Map<String,String>) theModifiableEnvField.get(theUnmodifiableEnvironment);
return modifiableEnv;
} catch(Exception e) {
throw new RuntimeException("Unable to access writable environment variable map.");
}
}
private Map<String, String> clearEnvironmentVars(String[] keys) {
Map<String,String> modifiableEnv = getModifiableEnvironmentMap();
HashMap<String, String> savedVals = new HashMap<String, String>();
for(String k : keys) {
String val = modifiableEnv.remove(k);
if (val != null) { savedVals.put(k, val); }
}
return savedVals;
}
private void setEnvironmentVars(Map<String, String> varMap) {
getModifiableEnvironmentMap().putAll(varMap);
}
@Test
public void myTest() {
String[] keys = { "key1", "key2", "key3" };
Map<String, String> savedVars = clearEnvironmentVars(keys);
// do test
setEnvironmentVars(savedVars);
}
인터넷으로 찾아보면 JNI랑 같이 할 수 있을 것 같아요.그런 다음 C에서 putenv()를 호출해야 하며 Windows와 UNIX 모두에서 동작하는 방식으로 (아마도) 해야 합니다.
만약 이 모든 것을 할 수 있다면, 나를 스트레이트 재킷에 가두는 대신 자바가 이것을 지원하는 것은 결코 어렵지 않을 것이다.
다른 곳에서 Perl을 말하는 친구는 환경 변수가 프로세스 글로벌하고 Java가 우수한 설계를 위해 적절한 분리를 위해 노력하고 있기 때문이라고 말합니다.
위에서 무리한 대답을 시도했지만 대부분 효과가 있었다.단, 상황에 따라서는 다음과 같은 예외가 발생합니다.
java.lang.String cannot be cast to java.lang.ProcessEnvironment$Variable
번 되었을 때 하며, 는 특정 으로 인해 합니다.이것은, 의 특정 내부 클래스의 실장 때문입니다.ProcessEnvironment.
경우,setEnv(..)
는 메서드에서 번 됩니다.때, 는, 로, 로, 로, 로, 로, 로, 로, 득, 득, 됩, 득.theEnvironment
첫 번째 되었습니다).setEnv(...)
타입인 「유형」에는 할 수 Variable,
클래스는 개인 입니다.ProcessEnvironment.
다음은 고정 버전(Scala)입니다.Java로 이관하는 것이 그리 어렵지 않길 바랍니다.
def setEnv(newenv: java.util.Map[String, String]): Unit = {
try {
val processEnvironmentClass = JavaClass.forName("java.lang.ProcessEnvironment")
val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
theEnvironmentField.setAccessible(true)
val variableClass = JavaClass.forName("java.lang.ProcessEnvironment$Variable")
val convertToVariable = variableClass.getMethod("valueOf", classOf[java.lang.String])
convertToVariable.setAccessible(true)
val valueClass = JavaClass.forName("java.lang.ProcessEnvironment$Value")
val convertToValue = valueClass.getMethod("valueOf", classOf[java.lang.String])
convertToValue.setAccessible(true)
val sampleVariable = convertToVariable.invoke(null, "")
val sampleValue = convertToValue.invoke(null, "")
val env = theEnvironmentField.get(null).asInstanceOf[java.util.Map[sampleVariable.type, sampleValue.type]]
newenv.foreach { case (k, v) => {
val variable = convertToVariable.invoke(null, k).asInstanceOf[sampleVariable.type]
val value = convertToValue.invoke(null, v).asInstanceOf[sampleValue.type]
env.put(variable, value)
}
}
val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
theCaseInsensitiveEnvironmentField.setAccessible(true)
val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]]
cienv.putAll(newenv);
}
catch {
case e : NoSuchFieldException => {
try {
val classes = classOf[java.util.Collections].getDeclaredClasses
val env = System.getenv()
classes foreach (cl => {
if("java.util.Collections$UnmodifiableMap" == cl.getName) {
val field = cl.getDeclaredField("m")
field.setAccessible(true)
val map = field.get(env).asInstanceOf[java.util.Map[String, String]]
// map.clear() // Not sure why this was in the code. It means we need to set all required environment variables.
map.putAll(newenv)
}
})
} catch {
case e2: Exception => e2.printStackTrace()
}
}
case e1: Exception => e1.printStackTrace()
}
}
유닛 테스트 중에 실행할 수 있는 라이브러리가 3개 있습니다.
Stefan Birkner의 System Rules and System Lambda - https://www.baeldung.com/java-system-rules-junit 에서는 다음과 같은 작업을 수행할 수 있습니다.
public class JUnitTest {
@Rule
public EnvironmentVariables environmentVariables = new EnvironmentVariables();
@Test
public void someTest() {
environmentVariables.set("SOME_VARIABLE", "myValue");
// now System.getenv does what you want
}
}
또는 System-Lambda의 경우:
@Test
void execute_code_with_environment_variables(
) throws Exception {
List<String> values = withEnvironmentVariable("first", "first value")
.and("second", "second value")
.execute(() -> asList(
System.getenv("first"),
System.getenv("second")
));
assertEquals(
asList("first value", "second value"),
values
);
}
위의 기능은 시스템스탭을 통해 JUnit 5 확장으로도 사용할 수 있습니다.
@ExtendWith(SystemStubsExtension.class)
class SomeTest {
@SystemStub
private EnvironmentVariables;
@Test
void theTest() {
environmentVariables.set("SOME_VARIABLE", "myValue");
// now System.getenv does what you want
}
}
시스템 스터브는 시스템 Lambda 및 시스템 규칙과 하위 호환되지만 JUnit 5를 지원합니다.
또는 JUnit Pioneer - https://github.com/junit-pioneer/junit-pioneer,도 있습니다.이것에 의해, 테스트시에 환경 변수를 주석을 개입시켜 설정할 수 있습니다.
코틀린 악마의 @hy의 악답입니다=)
@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun setEnv(newenv: Map<String, String>) {
try {
val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
theEnvironmentField.isAccessible = true
val env = theEnvironmentField.get(null) as MutableMap<String, String>
env.putAll(newenv)
val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
theCaseInsensitiveEnvironmentField.isAccessible = true
val cienv = theCaseInsensitiveEnvironmentField.get(null) as MutableMap<String, String>
cienv.putAll(newenv)
} catch (e: NoSuchFieldException) {
val classes = Collections::class.java.getDeclaredClasses()
val env = System.getenv()
for (cl in classes) {
if ("java.util.Collections\$UnmodifiableMap" == cl.getName()) {
val field = cl.getDeclaredField("m")
field.setAccessible(true)
val obj = field.get(env)
val map = obj as MutableMap<String, String>
map.clear()
map.putAll(newenv)
}
}
}
적어도 macOS 모하비에서는 동작하고 있다.
팀 라이언의 답변은 나에게 효과가 있었다...Groovy(예를 들어 스포크 컨텍스트)와 심플리시모:
import java.lang.reflect.Field
def getModifiableEnvironmentMap() {
def unmodifiableEnv = System.getenv()
Class cl = unmodifiableEnv.getClass()
Field field = cl.getDeclaredField("m")
field.accessible = true
field.get(unmodifiableEnv)
}
def clearEnvironmentVars( def keys ) {
def savedVals = [:]
keys.each{ key ->
String val = modifiableEnvironmentMap.remove(key)
// thinking about it, I'm not sure why we need this test for null
// but haven't yet done any experiments
if( val != null ) {
savedVals.put( key, val )
}
}
savedVals
}
def setEnvironmentVars(Map varMap) {
modifiableEnvironmentMap.putAll(varMap)
}
// pretend existing Env Var doesn't exist
def PATHVal1 = System.env.PATH
println "PATH val1 |$PATHVal1|"
String[] keys = ["PATH", "key2", "key3"]
def savedVars = clearEnvironmentVars(keys)
def PATHVal2 = System.env.PATH
println "PATH val2 |$PATHVal2|"
// return to reality
setEnvironmentVars(savedVars)
def PATHVal3 = System.env.PATH
println "PATH val3 |$PATHVal3|"
println "System.env |$System.env|"
// pretend a non-existent Env Var exists
setEnvironmentVars( [ 'key4' : 'key4Val' ])
println "key4 val |$System.env.key4|"
해당 환경변수에 의존하는 네이티브코드(dll)를 사용하는 현재 Java 프로세스에서 환경변수를 설정하는 것은 이 환경변수를 네이티브로 설정하는 경우에만 작동합니다.
이 예제의 대부분은 JVM의 맵을 변경하고 있지만 네이티브로 동작하지 않습니다.
제가 본 한 가지 방법은 JNI를 통해서입니다. 그것도 아마 효과가 있을 겁니다.또 다른 방법은 Kernel32 인터페이스(Windows 전용)를 사용하여 JNA 플랫폼을 사용하는 것입니다.다음은 예를 제시하겠습니다.
private static void setEnv(String key, String value) {
if(isWindows()) {
if (!Kernel32.INSTANCE.SetEnvironmentVariable(key, value)) {
System.err.println("Unable to set the environemnt variable: " + key);
}
}
}
OS와 같은 Unix의 경우 LibCAPI 인터페이스를 사용할 수 있지만 아직 사용하지 않았습니다.
환경변수를 (영구적으로) 설정(또는 갱신)해야 하는 유사한 요건이 있었기 때문에 이 스레드를 우연히 발견했습니다.
그래서 Command Prompt에서 환경변수를 영속적으로 설정하는 방법을 찾아봤는데 매우 간단했어요!
setx JAVA_LOC C:/Java/JDK
그리고 코드에 같은 것을 실장했습니다.사용한 것은 다음과 같습니다(가정 - JAVA_).LOC는 환경 변수 이름입니다.)
String cmdCommand = "setx JAVA_LOC " + "C:/Java/JDK";
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("cmd.exe", "/c", cmdCommand);
processBuilder.start();
ProcessBuilder는 cmd.exe를 실행하고 원하는 명령을 전달합니다.환경변수는 JVM/프로그램의 라이프 사이클과는 무관하므로 JVM을 종료하거나 시스템을 재부팅해도 유지됩니다.
리플렉트만 사용하시면 됩니다.setEnv("k1","v1")
private void setEnv(String key, String val) throws Exception {
getModifiableEnv().put(key, val);
}
private Map<String, String> getModifiableEnv() throws Exception {
Map<String, String> unmodifiableEnv = System.getenv();
Field field = unmodifiableEnv.getClass().getDeclaredField("m");
field.setAccessible(true);
return (Map<String, String>) field.get(unmodifiableEnv);
}
필요하다.
import java.lang.reflect.Field;
import java.util.Map;
Junit5를 사용하고 있는 저처럼 테스트에 관한 이 문제에 직면해 있다면 Junit-pioner는 매우 유용한 주석을 제공합니다.maven 릴리즈
예:
@Test
@SetEnvironmentVariable(key = "some variable",value = "new value")
void test() {
assertThat(System.getenv("some variable")).
isEqualTo("new value");
}
아무리 추천해도 부족해요.
jython variant는 @hy의 답변을 기반으로 하며 Windows에서 작동합니다.
def set_env(newenv):
from java.lang import Class
process_environment = Class.forName("java.lang.ProcessEnvironment")
environment_field = process_environment.getDeclaredField("theEnvironment")
environment_field.setAccessible(True)
env = environment_field.get(None)
env.putAll(newenv)
invariant_environment_field = process_environment.getDeclaredField("theCaseInsensitiveEnvironment");
invariant_environment_field.setAccessible(True)
invevn = invariant_environment_field.get(None)
invevn.putAll(newenv)
사용방법:
old_environ = dict(os.environ)
old_environ['EPM_ORACLE_HOME'] = r"E:\Oracle\Middleware\EPMSystem11R1"
set_env(old_environ)
Kotlin 버전입니다. 이 알고리즘에서는 환경으로부터 변수를 설정하고 가져올 수 있는 데코레이터를 만들었습니다.
import java.util.Collections
import kotlin.reflect.KProperty
class EnvironmentDelegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return System.getenv(property.name) ?: "-"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
val key = property.name
val classes: Array<Class<*>> = Collections::class.java.declaredClasses
val env = System.getenv()
val cl = classes.first { "java.util.Collections\$UnmodifiableMap" == it.name }
val field = cl.getDeclaredField("m")
field.isAccessible = true
val obj = field[env]
val map = obj as MutableMap<String, String>
map.putAll(mapOf(key to value))
}
}
class KnownProperties {
var JAVA_HOME: String by EnvironmentDelegate()
var sample: String by EnvironmentDelegate()
}
fun main() {
val knowProps = KnownProperties()
knowProps.sample = "2"
println("Java Home: ${knowProps.JAVA_HOME}")
println("Sample: ${knowProps.sample}")
}
Kotlin의 실장은 Edward의 답변을 바탕으로 최근에 실시했습니다.
fun setEnv(newEnv: Map<String, String>) {
val unmodifiableMapClass = Collections.unmodifiableMap<Any, Any>(mapOf()).javaClass
with(unmodifiableMapClass.getDeclaredField("m")) {
isAccessible = true
@Suppress("UNCHECKED_CAST")
get(System.getenv()) as MutableMap<String, String>
}.apply {
clear()
putAll(newEnv)
}
}
SpringBoot에서 작업할 경우 다음 속성에 환경 변수 지정을 추가할 수 있습니다.
was.app.config.properties.toSystemProperties
-D를 사용하여 파라미터를 초기 Java 프로세스에 전달할 수 있습니다.
java -cp <classpath> -Dkey1=value -Dkey2=value ...
언급URL : https://stackoverflow.com/questions/318239/how-do-i-set-environment-variables-from-java
'programing' 카테고리의 다른 글
static_cast와 repretter_cast의 차이점은 무엇입니까? (0) | 2022.07.16 |
---|---|
Vue 2는 클릭 가능과 이미지를 분할합니다. (0) | 2022.07.13 |
휴지 모드와 스프링 데이터 JPA의 차이점은 무엇입니까? (0) | 2022.07.13 |
변수를 함수 맨 위에 선언하시겠습니까, 아니면 별도의 범위로 선언하시겠습니까? (0) | 2022.07.13 |
Java에서 현재 날짜/시간을 가져오는 방법 (0) | 2022.07.13 |