[Spring boot] 환경 설정의 동작 원리와 애플리케이션 환경 나누기

Spring boot 프로젝트를 생성하고 난 후, Embedded Tomcat을 이용해 쉽게 애플리케이션을 시작해보고, 테스트할 수 있는 것 까지는 좋은 것이긴 한데, Embedded Tomcat에 대한 포트 주소 등의 설정은 어떻게 하는 것일까?

 

Property

기존의 Spring에서는 모든 설정을 XML 파일로 사용했다면,  Spring boot에서는 Embedded Tomcat, Application 설정 관련 및 기타 정적인 값을 키 값 형식으로 관리합니다. 

Spring boot 프로젝트를 생성하면, 자동 만들어지는 application.properties는 이러한 설정을 해주는 파일입니다. 현재 애플리케이션을 실행하면 8080 포트로 설정되지만, 이 포트 주소를 바꾸고 싶다면, 아래와 같이 설정을 추가해주시면 됩니다.

그러면 이제부턴 1412 포트 주소로 애플리케이션이 실행되는 것이죠.

 

Auto Configuration

어떻게 이런 것이 저렇게 단순한 값을 설정하는 것만으로도 가능한 것일까요? 그것은 바로 여러분들이 만드신 Spring boot 프로젝트의 메인 코드에 그 답이 있습니다.

이 메인코드에는 SpringBootApplication 어노테이션이 있습니다. 이 어노테이션의 코드를 조금 살펴 보자면..

이렇게 @EnableAutoConfiguration 자동 환경 설정이라는 어노테이션이 달려져 있습니다. 이는 Spring boot에서 크게 개선된 점이자 아주 큰 장점입니다. 

왜냐하면, 이 어노테이션 하나로, Web, H2, JDBC를 비롯한 약 100여 개의 자동 설정을 제공하기 때문이죠. Embedded Tomcat에서 기본 설정 값으로 8080을 주어주는 것도 바로 이 어노테이션의 영향 떄문입니다. 

더욱이, 해당 애플리케이션에서 새로이 추가되는 라이브러리 (JAR)는 Spring boot 자동 환경 설정에 의거, 설정이 자동 적용되는데, 만약 H2 의존성이 클래스 경로에 존재한다면, 자동으로 In-memory DB에 접근하는 것이죠. 이 말은 구체적으로 우리가 application.properties에서 H2 설정 파일을 입력하는 것만으로도 별도의 구현 코드 작성 없이 자동으로 해당 애플리케이션이 In-memory DB에 접근한다는 것입니다. (와우, 엄청 좋죠.. )

좀 더 구체적으로 어떻게 동작하는지 한 번 보도록 하자면... META-INF/spring.factories에 정의된 자동 설정할 클래스들을 먼저 불러오는데, 여기에 H2, Web 등 100 여개의 설정이 미리 정의 되어 있고, 그 클래스들을 로드하여 자동 설정을 만들어내는 것입니다. 단, 이렇게 하게 되면, 중복되는 빈이 설정될 경우가 생길텐데, 이를 대비하여 처리한 로직이 눈에 띄는 게 있습니다.

바로 Set을 이용해서 제외할 설정들을 저장하는데, 여기서 제외할 설정들은 중복된 설정 removeDuplicates 메소드를 이용해 이미 추려진 것이죠. 마지막으로 이 중에서 프로젝트에 사용되는 Bean만 Import할 자동 설정 대상으로 선택됩니다.

그렇다면, 이들 클래스의 등록과 자동 설정에 사용되는 파일들은 어떤 것일까요?

  • META-INF/spring.factories
    - 자동 설정 대상 클래스 목록으로 @EnableAutoConfiguration 사용시, 해당 클래스들은 자동 설정 대상이 된다.
  • META-INF/spring-configuration-metadata.json: 자동 설정에 사용할 Property 정의 파일이다.
  • org/springframework/boot/autoconfigure: 미리 구현해놓은 자동 설정 리스트이다. 대부분 자바 설정 방식을 따른다.

그렇다면 우리가 바꾼 Embedded Tomcat의 LISTEN PORT 설정값도 있겠죠? 네, 맞습니다. 여기에 있습니다.

실제로 이 곳에는 Spring REST 뿐 아니라 Spring Security 등 다양한 모듈에 대한 자동 설정 값이 담겨져 있습니다. 다른 모듈에 대해서는 차후 포스트에서 다룰 것이지만, 왜 Spring boot에서 이런 Key-value 형태의 값 만으로 서버 애플리케이션 설정이 바뀔 수 있는지 이해가 될 것이라고 생각합니다.

좀 더 자세한 내용에 대해서는 자동 설정에 대한 파트를 다른 포스트에서 한 번 더 다뤄보도록 하겠습니다.

 

YAML

여태까지 Property를 사용해서 Spring boot의 환경 설정을 다뤄봤습니다. 하지만 Properties에서는 표현의 한계점이 존재하여 Spring Project 팀에서도 YAML을 사용하고 있습니다.

본래, YAML을 사용하려면 SnakeYAML 모듈을 별도로 설치해야 하지만, 이제는 Spring boot Starter에 이 모듈이 기본으로 내장되어 있기 때문에 별도로 의존성을 추가할 필요 없이 application.properties를 application.yml로만 이름을 바꿔주면 됩니다.

만약 application.properties와 application.yml 파일이 두 개 다 존재하면 어떻게 되나요? 
---> 그럴 땐 application.yml 파일만 오버라이드 되어 적용됩니다.

 

Environment Settings

애플리케이션을 개발하다보면, 공통적인 고민 거리는 바로 배포 후의 문제입니다. 개발 환경에서는 잘 동작하였다가도 항상 배포 후 프로덕션 환경에서는 문제가 생기기 때문입니다.

이러한 문제를 완화시킬 수 있는 방법에는 CI/CD 환경을 이용하는 방법이 있습니다. 하지만 이 방법을 쓰게 되면, 실제 운영 환경에서 사용하는 데이터베이스나 사용자 계정 등의 설정을 위해 우리는 서버의 환경 설정을 매번 바꿔야 합니다. 

이러한 불편함을 해소하기 위해 우리는 애플리케이션에서 환경을 나누는 방법이 존재하는데, 우리는 이러한 환경을 나누기 위해서 어떻게 설정 파일을 구성해야 하고, Spring boot에서 어떤 것을 이용하면 되는지 알아보도록 하겠습니다.

먼저 개발, 운영, 테스트 환경 이렇게 3개로 나눈다고 가정하고, 각각 YAML 파일을 위와 같이 생성해줍니다.

# application-dev.yml

spring:
  profiles: dev

server:
  port: 1412
# application-prod.yml

spring:
  profiles: prod

server:
  port: 80
# application-test.yml

spring:
  profiles: test

server:
  port: 8081

위와 같이 각 파일에 dev, prod, test 등 3가지 환경을 만들고, 저장합니다.

# application.yml

server:
  port: 8080
spring:
  profiles:
    active: dev

원하는 환경을 적용하고자 할 경우에는 3가지 방법이 있습니다. 첫 번째 방법은 application.yml 파일을 하나 만들어 위와 같이 코드를 추가하는 데, active 쪽의 값을 원하는 환경으로 설정하시면 됩니다.

만약, 해당 환경이 존재하지 않을 경우에는 위의 포트 주소로 실행됩니다.

이 외에도 IntelliJ IDEA에서 프로젝트 설정을 통해서도 환경 설정을 진행할 수 있습니다.

처음에는 코틀린 실행 환경만 제공하기 때문에 별도로 Spring boot의 환경 설정을 만들어줘야 합니다. Templates 버튼을 클릭하여 Spring boot Configuration을 추가해줍니다.

그런 다음, 적절한 이름을 입력하고, Main class에 Spring boot Main Application 클래스를 넣어준 다음, Active Profiles에 원하는 환경 설정 파일을 입력해주면 됩니다.

기본적으로 Spring boot Configuration으로 애플리케이션이 실행될 경우, application.yml 파일에 정의된 actives는 무시됩니다.

comments powered by Disqus

Tistory Comments 0