Spring/Spring Boot

[Spring Boot] 2-2. Core Features: Externalized Configuration

noahkim_ 2023. 10. 9. 01:15

Spring Boot는 외부 설정을 통해 같은 코드를 다양한 환경에서 실행할 수 있게 지원합니다.

이 설정은 프로퍼티 파일, YAML 파일, 환경 변수, 명령행 인자 등을 통해 제공될 수 있습니다.

이러한 설정 값들은 @Value 어노테이션 또는 @ConfigurationProperties를 사용하여 애플리케이션의 빈에 주입될 수 있습니다.

Spring Environment는 여러 PropertySource를 관리하며, 각 PropertySource는 정해진 우선순위에 따라 동작합니다.

 

동일한 프로퍼티 키가 여러 PropertySource에 존재할 경우, 늦게 등장하는 순서의 PropertySource 값으로 오버라이드됩니다.

 

0. PropertySource 순서

  1. Default properties (SpringApplication의 setDefaultProperties()로 설정됩니다)
  2. @PropertySource 어노테이션으로 주입된 값 (@Configuration과 함께 사용됩니다)
  3. Config data (application.properties)
  4. RandomValuePropertySource
  5. OS environment variables
  6. Java System properties (System.getProperties()로 접근할 수 있다)
  7. JNDI attribute (java:comp/env)
  8. ServletContext의 init parameter
  9. ServletConfig의 init parameter
  10. SPRING_APPLICATION_JSON properties
  11. Command line arguments
  12. properties on test annotation
  13. @DynamicPropertySource
  14. @TestPropertySource
  15. Devtools - $HOME/.config/spring-boot

 

Config data 순서

  1. application.properties (or yaml) packaged inside jar
  2. application-{profile}.properties (or yaml) packaged inside jar
  3. application.properties (or yaml) outside of packaged jar
  4. application-{profile}.properties (or yaml) outside of packaged jar

 

1. Accessing Command Line Properties

  • SpringApplication은 command line argument를 PropertySource로 객체화하고 Environment에 추가합니다.
  • 위 순서를 참고하였을 때, command line argument은 더 늦게 나오는 순서이므로 file-based properties값을 오버라이드합니다.
  • command line argument를 Environment에 추가를 끄고싶을 경우, SpringApplication.setAddCommandLineProperties(false)를 호출합니다.

 

2. JSON Application Properties

  • 몇몇의 property key는 사용될 수 없습니다.
  • 이를 허가하고자 json structure에 properties key를 encoding하여 주입합니다.
$ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar
$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar
$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'
  • spring.application.json 혹은 SPRING_APPLICATION_JSON을 이용하여 파싱할 수 있습니다.

 

3. External Application Properties

  • Spring Boot는 자동적으로 config data를 찾아 로드합니다.
  • config data를 찾기위해 기본적으로 설정된 클래스 패스와 디렉토리가 있습니다.

 

classpath

  1. root classpath
  2. /config package classpath

 

directory

  1. current directory
  2. config/ subdir in current directory
  3. child directory of config/ subdir
(current directory : "Spring Boot가 실행되는 디렉토리")

 

spring.config.name

  • config data 파일의 이름을 지정하는 property key 입니다.

 

spring.config.location

  • config data 파일의 기본 경로를 명시적으로 지정하는 property key 입니다.
  • spring.config.location 하위 디렉토리의 파일도 읽혀집니다.

 

$ java -jar myproject.jar --spring.config.location=\
    optional:classpath:/default.properties,\
    optional:classpath:/override.properties
  • spring.config.location 는 comma-separated list로 전달될수 있습니다.
  • 순서대로 읽혀지며 나중에 읽혀진 config data가 이전것을 오버라이딩 합니다.

 

spring.config.name=myapp
spring.config.location=classpath:/default-config/;file:/etc/myapp/
  • profile별 복수개의 config data를 그룹핑하여 설정을 함께 셋업할 수 있습니다.
  • locations들을 그룹핑하기 위해 각 location을 세미콜론으로 구분하여 한줄로 작성합니다.

 

spring.config.additional-location

  • 기본 config data 파일 이외로, 추가적으로 적용하고자 하는 파일의 location을 지정하는 property key 입니다.
  • additional-location의 경로로 읽어온 config data는 기본 config data을 오버라이딩합니다.
  • 이러한 읽기 순서는 기본 config data는 default 값 설정을, additional config data은 구체적인 설정을 하도록 설계되었습니다.

 

Optional Locations

$ java -jar myproject.jar --spring.config.location=\
    optional:classpath:/default.properties,\
    optional:classpath:/override.properties
  • "optional:" spring.config.location 혹은 spring.config.additional-location에서 location의 prefix 입니다.
  • Spring Boot는 location에 config data가 없다면 ConfigDataLocationNotFoundException이 발생합니다.
  • ConfigDataLocationNotFoundException이 발생하면 서버는 실행되지 않습니다.
  • optional locations를 사용할 경우 경로에 config data가 없더라도 예외가 발생하지 않습니다.

 

Wildcard Locations

  • location에 *(와일드카드)를 사용할 경우 해당 경로의 하위 파일들을 모두 읽습니다.
    • location들은 절대 경로를 기준으로 알파벳 순으로 config data 파일을 읽습니다.
    • 로컬 파일 시스템의 외부 디렉토리를 지정할 때만 사용할 수 있습니다.
    • classpath에 위치한 내부 리소스를 가리키는 용도로 쓸 수 없습니다.
  • 분리된 config data를 함께 읽어 설정을 구성할 경우, 와일드카드를 활용하여 적절하게 경로들을 가리킬 수 있습니다.
    • 주로 kubernetes와 같은 플랫폼에서 사용하기에 유용합니다.

 

Profile Specific Files

  • spring.profiles.active 프로파일로 active profile을 합니다.
  • Spring Boot는 특정 profile의 config data를 application-{profile} 컨벤션으로 인식합니다.
  • Spring Boot는 기본 config data과 profile config data을 둘다 읽습니다.
    • 기본 config data로 디폴트값을 설정하고
    • profile config data로 오버라이딩합니다
  • active profile을 여러개 설정할 경우 last-win 전략이 적용됩니다.
    • comma-separated list에서 나중에 기입된 전략이 맨 마지막에 읽혀 오버라이딩합니다.
  • active profile을 설정하지 않을 경우 default profile이 자동 적용됩니다.

 

Importing Additional Data

  • spring.config.import property를 사용하여 추가적으로 config data를 가져올 수 있습니다.
  • 외부 저장소에서 가져올 수 있습니다. (Apache ZooKeeper, Netflix Archaius 등)
  • ConfigDataLocationResolver, ConfigDataLoader
    • import 커스터마이징 객체를 지원하는 클래스를 제공합니다.

 

Importing Extensionless Files

  • 확장자가 없는 파일을 import할 수 있습니다.
  • 일부 클라우드 플랫폼에서는 볼륨 마운트된 파일에 파일 확장자를 쓸 수 없습니다.
  • 이러한 파일을 import하기 위해 hint를 제공하는 문법이 있습니다.
spring.config.import=file:/etc/config/myconfig[.yaml]

 

Using Configuration Trees

  • "configtree:" : 클라우드 플랫폼 내에 config data가 있을 경우 참조를 가리키는 키워드입니다.
  • 클라우드 플랫폼에서 Spring Boot 애플리케이션을 운영할 때 사용됩니다.

 

etc/
  config/
    myapp/
      username
      password
spring.config.import=optional:configtree:/etc/config/
  • spring boot에서 클라우드 플랫폼의 config data를 접근하여 읽고 propertysource로 등록합니다.
  • myapp.username, myapp.password가 등록됩니다.

 

 

Property Placeholders

  • config data를 읽어드릴 때 값 참조 및 디폴트 값 설정을 지원하는 문법입니다.

 

app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
  • ":" : 기본값을 설정하는 키워드입니다
  • ${property key} : 이전에 선언된 property의 값을 참조하는데 사용되는 키워드입니다.

 

  • relaxed binding 전략이 적용됩니다.
${demo.item-price}
-> demo.item-price
-> demo.itemPric
-> DEMO_ITEMPRICE

 

Working With Multi-Document Files

  • Spring Boot는 하나의 config data 파일에 독립적으로 여러 profile의 config data를 작성할 수 있습니다.
  • 활성화 조건을 기입할 수 있으며, 조건에 일치할 경우에만 적용됩니다
  • key가 중복될 경우, 나중에 입력된 값으로 오버라이딩 됩니다.

 

spring:
  application:
    name: "MyApp"
---
spring:
  application:
    name: "MyCloudApp"
  config:
    activate:
      on-cloud-platform: "kubernetes"
spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
  • .properties 파일 구분자 : #--- or !---
  • .yaml 파일 구분자 : ---

 

Activation Properties

  • 특정 환경에서 동작하는 조건을 명시하는 property key 입니다.
  • spring.config.activate.on-cloud-platform : 사용되는 플랫폼
  • spring.config.activate.on-profile : 사용되는 프로파일
myprop=always-set
#---
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
myotherprop=sometimes-set

 

 

 

참고