스프링에서는 환경 변수, 데이터 소스 (DataSource) 등 프로그램이 돌아갈 때 필요한 정보들을 보관할 수 있도록 application.properties
또는 application.yaml
을 지원한다. 그런데 개발하는 환경이 달라질 때 마다 이들의 값들을 매번 바꾸는 것은 귀찮은 작업이 되기도 한다.
예시로, 실제 개발 환경에는 MySQL을 쓰고 ddl-auto
가 none
으로 되는 게 맞지만, 로컬 개발 환경에서는 매번 확인해보는 게 좋기 때문에 h2 인메모리 데이터베이스를 쓰면서 ddl-auto
를 create
로 하는 게 적합할 것이다.
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/디비_이름?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
username: MySQL 관리자 이름
password: MySQL 비밀번호
jpa:
hibernate:
ddl-auto: none
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:디비_이름
username: sa
password:
이때 이 둘을 자주 바꿔 갈아끼우다보면 때로는 잘못 작성하는 일도 발생할 것이다. (일부분만 바꾼다거나, 값을 까먹거나, 또는 주석을 쓴다고 해도 깔끔하지 않은 측면이 있다.)
이제 그렇다면 이러한 문제점을 해결하기 위해 YAML 파일들을 분리해보자.
크게 로컬 환경, 개발 환경으로 나누어보겠다. (운영 환경은 운영하고 있는 예가 없기 때문에 보류) (그 전에 지켜야 할 규칙들이 있다.)
먼저, YAML 파일 이름을 정할 때는 나름의 규칙을 지켜야 한다.
스프링에서는 application-{profile}.yml
을 통해 이들을 구분하고 활용할 수 있다. 여기에서 {profile}
에 원하는 이름을 작성하면 된다.
이 내용은 공식 문서에서도 나와있다.
Profile-specific application properties outside of your packaged jar (
application-{profile}.properties
and YAML variants).
Profile-specific application properties packaged inside your jar (application-{profile}.properties
and YAML variants).
만약 파일 보관을 application.yml
과 같은 곳에 전부 넣어둘 것이냐, 또는 다른 폴더들을 만들어 넣어둘 것이냐에 따라 작성 방식이 살짝 달라진다. 이 부분은 아래 설명을 참고한다.
마지막으로, application.yml
을 작성하면 된다. 이 위치는 변경되면 안 된다. (추후 경로를 바꿀 수 있긴 하지만 그러지 않는 게 편하다.)
아직 정확히 어떤 식으로 작성해야 하는지 감이 잘 오지 않을테니, 실제 예시를 통해 보도록 하자.
구조는 다음과 같이 되어있다.
project
├── src
│ ├── main
│ ├── java
│ ├── resources
│ │ ├── static
│ │ ├── templates
│ │ ├── yaml
│ │ │ ├── logging
│ │ │ │ └─ application-log.yml
│ │ │ ├── application-dev.yml
│ │ │ └─ application-local.yml
│ │ └─ application.yml
...
나는 기본적인 application.yml
을 두고, 로그 기능들이 담겨진 application-log.yml
을 yaml/logging
에, 개발 환경과 로컬 환경을 뜻하는 application-dev.yml
과 application-local.yml
을 yaml
에 보관한다고 설정했다.
spring:
config:
activate:
on-profile: dev
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
username: {데이터베이스 관리자 이름}
password: {데이터베이스 비밀번호}
jpa:
hibernate:
ddl-auto: none
ddl-auto
옵션을 none으로 적용했다.spring:
config:
activate:
on-profile: local
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:test
username: sa
password:
ddl-auto
를 작성하지 않아도 문제 없다.spring:
config:
activate:
on-profile: log
jpa:
properties:
hibernate:
# show_sql: true # System.out 방식 로그
format_sql: true
highlight_sql: true
use_sql_comments: true
logging:
level:
org:
hibernate:
SQL: debug # logger 방식 로그
orm:
jdbc:
bind: trace
spring:
config:
import:
- classpath:/yaml/application-prod.yml
- classpath:/yaml/application-dev.yml
- classpath:/yaml/application-local.yml
- classpath:/yaml/logging/application-log.yml
profiles:
group:
logging: dev, log
active: logging
# active: local
application.yml
과 같은 곳에 있다면 spring.config.import
를 작성할 필요가 없다. 이것은 다른 폴더에 있을 때 스프링이 인식할 수 있도록 하기 위해 작성한 것이다.spring.profiles.active
에 해당 profile
값을 넣으면 된다.spring.profiles.group
에 {원하는 이름}: {profile 1}, {profile 2}
등과 같이 그룹화시키고, spring.profiles.active
에 해당 {원하는 이름}을 작성해두면 된다.또한, application.yml을 제외한 각 문서들을 보면 다음과 같은 내용이 있다.
spring:
config:
activate:
on-profile: log
이것은 자신이 실행될 profile
을 의미한다. 만약 이것을 작성해놓지 않는다면, application.yml
에서 import
한 순서에 따라 맨 마지막에 작성된 yml
로 덮어씌워지게 된다. (모두 다 같은 폴더에 위치시킨 다음 spring.config.activate.on-profile
을 작성해놓지 않을 수도 있겠지만 이 경우는 시도해보진 않았다.)
application-log.yml
을 사용했기에 쿼리가 나오고, application-local.yml
을 사용했기에 create table
이 나온다.
drop table if exists member
[Hibernate]
drop table if exists member
2023-08-19T16:47:04.656+09:00 DEBUG 12287 --- [ main] org.hibernate.SQL :
create table member (
id bigint not null auto_increment,
name varchar(255),
primary key (id)
) engine=InnoDB
[Hibernate]
create table member (
id bigint not null auto_increment,
name varchar(255),
primary key (id)
) engine=InnoDB
application-dev.yml
만 사용했기에 쿼리가 나오지 않는다.
2023-08-19T16:47:32.556+09:00 INFO 12294 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2023-08-19T16:47:32.593+09:00 INFO 12294 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2023-08-19T16:47:32.928+09:00 WARN 12294 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2023-08-19T16:47:33.307+09:00 INFO 12294 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-08-19T16:47:33.318+09:00 INFO 12294 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 4.435 seconds (process running for 5.046)
2023-08-19T16:47:37.165+09:00 INFO 12294 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-08-19T16:47:37.166+09:00 INFO 12294 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-08-19T16:47:37.168+09:00 INFO 12294 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
부족하거나 보완할 점이 있다면 댓글 부탁드립니다 😃