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
해결
- 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 우선순위는 작성 순서와도 연관이 있었구나