시냅스

JVM, Spring 에서의 시스템 변수와 환경변수 이해 본문

Java, Spring

JVM, Spring 에서의 시스템 변수와 환경변수 이해

ted k 2023. 11. 28. 21:48
정보 관리를 위해 Java/Spring 환경에서의 시스템 변수, 환경변수의 활용에 대한 글을 작성했습니다.
Vault 와 같은 툴을 사용할 수도 있지만 그 전에 application level 에서의 이해를 돕기 위해 글을 작성하였습니다.

 

 

시스템 중요 정보를 외부에서 할당할 때 정보은닉을 지키며 할당한 데이터를 사용하는 방법에 대해 알아봅니다.

아래에서는 OS 환경 변수, 시스템 변수, 나아가 application.yml 이 어떤 순서로 할당되는지에 대해 알아봅니다.

 

System.getenv

  • JVM 이 실행되는 운영체제의 환경변수를 가져옵니다.
  • 대개 apllication 을 실행하는 OS 의 환경변수 이거나 build time 에 shell / Docker / k8s 등에서 설정하기도 합니다.
  • OS 전역의 변수를 가져올 수 있습니다.
  • Java application이 시작될 때, 부모 프로세스의 환경변수를 복제하여 상속받습니다. (Clone Inheritance)
  • 따라서 OS에서 복사해온 immutable 한 변수이므로 변경 / 수정이 불가능합니다.
public class Main {
    public static void main(String[] args) {
        String envVar = System.getenv("MY_ENV_VAR");
        System.out.println("Environment variable: " + envVar);
    }
}

 

 

System.getProperty

  • 로컬 시스템 및 구성에 대한 정보를 제공합니다.
  • JVM 에 국한됩니다.
  • VM Options 로 설정할 수 있습니다.
    • -d 옵션을 사용합니다.
  • runtime 에 변경 / 수정이 가능합니다.
// java -Dmy.sys.prop=hello
public class Main {
    public static void main(String[] args) {
        String sysProp = System.getProperty("my.sys.prop");
        System.out.println("System property: " + sysProp); // System property: hello
        System.setProperty("my.sys.prop", "hello agian");
        System.out.println("System property: " + sysProp); // System property: hello again
    }
}

 

 

Spring 환경변수 참조

  • Environment 인터페이스, 혹은 @Value, @ConfigurationProperties 을 사용하여 환경변수, 시스템 변수를 참조할 수 있습니다.
    • 이때, 같은 key 를 가진다면 우선순위에 따라 할당됩니다.
    • 우선 순위 - Spring 공식문서
    • 또한 Spring Boot 에서 값을 할당해줘야 하므로 Spring app 의 context load 이전에는 참조할 수 없습니다.
      • 만약 할당한 환경변수가 context 종속적(build time 에만 사용)이고 context load 이전 (@PostConstruct 등)에 변수를 사용해야 한다면 이 방법으로는 사용할 수 없습니다.
      • 아래에서 Spring 의 생명주기와 함께 변수 할당 시점을 설명합니다.
  •  application.yml
    • SpEL 의 꼴로 시스템 / 환경 변수를 할당할 수 있게 합니다. ( ${} )
    • SpEL 의 value 는 application 이 시작되는 단계에 할당됩니다.
    • Spring Boot 에서 제공하는 AutoConfiguration 에 많이 활용됩니다.
      • DB, Redis ...etc
# application.yml
my:
  prop: ${SOME_DATA} # SOME_DATA=hello

 

@RestController
public class MyController {

    @Value("${my.prop}")
    private String myProp;

    @GetMapping("/prop")
    public String getProp() {
        return "Property value: " + myProp; //Property value: hello 
    }
}

 

 

Spring Lifecycle 로 보는 변수 할당 시점

  • JVM 시작
    • OS 환경변수 참조 가능 (System.getenv)
    • JVM Property 참조 가능 (System.getProperty)
  • spring app context initializing
    • spring core
    • 이때 bean 에 대한 주입을 마치고 나면 @PostContruct 가 실행됩니다.
    • 비슷한 시기에 BeanFactoryPostProcessor 에서 @Value 에 참조 값들을 확인하고 설정합니다.
    • 따라서 같은 시기에 할당되므로 @PostConstruct 에서는 @Value 를 참조할 수 없습니다.
    • 또는 @Value 자체를 Constructor 로 DI 받아야 합니다.
  • spring web initializing
    • Spring MVC, DispatcherServlet, web...
  • context load
  • 참고
    • application.yml 의 value ( ${} ) 는 spring app context initializing 단계에서 이미 할당되어 있습니다.
    • 다만, 그 값을 불러오는 @Value 등에서 사용이 bean 이 다 주입된 이후에 가능합니다.
    • 따라서 application.yml 에 설정된 값들을 통해 AutoConfiguration 이 가능합니다.

 

 

참고

https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config

 

Core Features

In the absence of an Executor bean in the context, Spring Boot auto-configures an AsyncTaskExecutor. When virtual threads are enabled (using Java 21+ and spring.threads.virtual.enabled set to true) this will be a SimpleAsyncTaskExecutor that uses virtual t

docs.spring.io

 

https://www.baeldung.com/java-system-get-property-vs-system-getenv

 

Comments