본문 바로가기

스프링 부트

application.properties VS application.yml 그리고 YAML을 사용하면서 겪은 문제점

application.properties 설정

Spring Boot는key-value 형식을 사용하는application.properties파일설정 값들을 가져와 쓸 수 있다.

spring.datasource.url=jdbc:h2:dev
spring.datasource.username=SA
spring.datasource.password=password

각 라인은 단 하나의 key-value로 이루어져있다.
닷(.)을 이용해 계층적 구조를 이룰 수 있다.

Placeholders

값을 지정할 때, ${} 을 사용해 다른 환경 변수의 값을 참조할 수 있다.

app.name=MyApp
app.description=${app.name} is a Spring Boot application

List

하나의 속성에 값이 다른 value가 있는 경우 배열 인덱스로 List 구조를 나타낼 수 있다

application.servers[0].ip=127.0.0.1
application.servers[0].path=/path1
application.servers[1].ip=127.0.0.2
application.servers[1].path=/path2
application.servers[2].ip=127.0.0.3
application.servers[2].path=/path3

여러개의 Profile

스프링 2.4부터 한 파일에서 다중 Profile를 정의할 수 있도록 지원한다.
'#---' 로 Profile을 구별한다.
spring.config.activate.on-profile로 profile을 구별할 수 있는 이름을 준다.

logging.file.name=myapplication.log
bael.property=defaultValue
#---
spring.config.activate.on-profile=dev
spring.datasource.password=password
spring.datasource.url=jdbc:h2:dev
spring.datasource.username=SA
bael.property=devValue
#---
spring.config.activate.on-profile=prod
spring.datasource.password=password
spring.datasource.url=jdbc:h2:prod
spring.datasource.username=prodUser
bael.property=prodValue

루트 수준의 property 속성 정의도 가능한데,
예시에서 각각의 property에서 정의되지 않은 logging.file.name는 모든 property에서 동일하다.

여러개 파일의 Profile

다음과 같이 application-name.properties 와 같은 네이밍으로 여러 profile를 정의할 수 있고,
jar 빌드시 다음과 같은 명령어로 환경에 맞는 profile을 쓸 수 있다.

nohup java -jar -Dspring.profiles.active=prod ${JAR_LOCATION} 1> log-prod.md 2>&1  &

YAML 설정

Java 속성 파일뿐만 아니라Spring Boot 애플리케이션에서 YAML기반의 설정 파일을사용할 수도 있다.
YAML은 계층 적 구성 데이터를 지정하기위한 조금 더 편리한 형식이다.

spring:
    datasource:
        password: password
        url: jdbc:h2:dev
        username: SA

확실히 반복되는 key 접두사가 제거되고 계층적인 구조가 명확히 드러난다.

List

yaml에서는 다음과 같은 방법으로 list를 표현한다.

application:
    servers:
    -   ip: '127.0.0.1'
        path: '/path1'
    -   ip: '127.0.0.2'
        path: '/path2'
    -   ip: '127.0.0.3'
        path: '/path3'

여러개의Profile

스프링 버전과 관계없이 YAML은 한 파일에서 다중 Profile를 정의할 수 있다.
여기서는 '---' 로Profile을 구별한다.
마찬가지로 spring.config.activate.on-profile로 profile을 구별할 수 있는 이름을 준다.

logging:
  file:
    name: myapplication.log
---
spring:
  config:
    activate:
      on-profile: staging
  datasource:
    password: 'password'
    url: jdbc:h2:staging
    username: SA
bael:
  property: stagingValue

주의

application.properties와 application.yml를 동시에 사용하지 않도록 주의하자.
이 둘 간의 순서 차이가 있는데, application.properties가 항상 나중에 로드되어 YAML에 정의한 profil 설정이 덮어씌여질 수 있기 때문이다.

 

참고자료

Using application.yml vs application.properties in Spring Boot


놀토에서 Profile 설정 - YAML

우리는 앞서 봤듯이 YAML이 계층 구조가 명확히 드러나며 가독성이 좋았기에 YAML로 한 파일에서 Profile 설정을 구분하였다.

다 좋지만 우리가 사용하면서 겪은 문제를 공유하며 주의할 점을 적는다면
YAML은 닷(.)과 인덴트로 계층을 구분하고 있다.
때문에 계층 구조에서 인덴트가 조금이라도 잘못되거나 벗어나면 값을 못읽거나 오류를 발생시키기에 인덴트에 주의하자.
필요한 값 다 작성한 거 같은데 왜 실패하지... 싶으면 먼저 인덴트를 올바르게 썼나 함 봐보세요.
(실제로 우리도 이로 발생한 오류 때문에 딴데서 삽질을 꽤나 했었다 ㅎ)

YAML을 사용하면서 겪은 문제들과 해결 법

Profile 별로 include를 다르게 하고 싶어요

prod 설정에서 realdb 설정을 include하고 싶은데 다음과 같이 작성하면 애플리케이션 빌드 자체가 실패하더라.

spring:
  profiles:
    include: realdb
  config:
    activate:
      on-profile: prod
  • 이런식으로 작성할 경우 - run fail

image

해결

  • 2.4 주요 변경사항으로 include 는 특정 profile 이 적용된 곳에서는 사용할 수 없음
  • 때문에 on-profile 과 include 가 공존할 수 없음
  • 2.4 에 추가된 스펙인 spring.profiles.group 속성을 사용해 문제를 해결

application.yml

spring:
  profiles:
    active: dev
    groups :
      prod : realdb
---
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:nolto
    username: sa
    password:
  h2:
    console:
      enabled: true
---
spring:
  config:
    activate:
      on-profile: test
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb
    username: sa
    password:
  h2:
    console:
      enabled: true
---
spring:
  config:
    activate:
      on-profile: prod
  jpa:
    properties:
      hibernate:
        ddl-auto: create# 한번 실행 후 추후 변경
dialect: MariaDBDialect

---
spring:
  jpa:
    properties:
      hibernate:
        format_sql: true
        ddl-auto: create
        dialect=org:
          hibernate:
            dialect: H2Dialect
    show-sql: true
logging:
  level:
    org:
      hibernate:
        type:
          descriptor:
            sql:
              BasicBinder: TRACE

application-realdb.yml (분리)

---
spring:
  datasource:
    url: jdbc:mariadb://우리IP:3306/nolto
    username: 비밀이지롱
    password: 비밀이지롱
    driver-class-name: org.mariadb.jdbc.Driver
  config:
    activate:
      on-profile: realdb

참고

 

yml 실행 순서때문에 발생한 table drop

  • 짤막한 깨달음임
  • Prod 서버는 사실 아직 리빌드 하는 경우가 드물었다.
  • 그러다 리빌드하고 서버를 재구동 했는데...
  • 분명 prod 환경에서는 ddl-auto: validate로 변경했는데, create 옵션이 먹히고 있다?
  • 덕분에 데이터가 다 날아갔다.
  • ddl-auto: validate 설정이 왜 묻혔을까

문제의 yml

spring:
  profiles:
    active: dev
    group:
      prod: realdb
---
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:nolto
    username: sa
    password:
  h2:
    console:
      enabled: true
---
spring:
  config:
    activate:
      on-profile: test
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb
    username: sa
    password:
  h2:
    console:
      enabled: true
---
spring:
  config:
    activate:
      on-profile: prod
  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
---
spring:
  jpa:
    properties:
      hibernate:
        format_sql: true
        ddl-auto: create
        dialect=org:
          hibernate:
            dialect: H2Dialect
    show-sql: true

이유

  • yml은 작성 순서가 우선 순위의 영향을 받는다.
  • Prod 환경에서는 validate 설정이 맞지만 작성 순서의 가장 마지막에서 ddl-auto: create를 하고 있어 덮어 씌워지게 되었다.
  • yml 우선순위는 작성 순서와도 연관이 있었구나