본문 바로가기
Spring Study/SpringBoot

[SpringBoot] 외부 설정과 프로필

by 정재인 2023. 11. 30.

외부 설정이란?

하나의 애플리케이션을 여러 다른 환경에서 사용해야 할 때가 있다. 대표적으로 개발이 잘 진행되고 있는지 내부에서 확인하는 용도의 개발 환경, 그리고 실제 고객에게 서비스하는 운영 환경이 있다.

  - 개발 환경: 개발 서버, 개발 DB 사용

  - 운영 환경: 운영 서버, 운영 DB 사용

 

 

배포 환경과 무관하게 하나의 빌드 결과물을 만든다. 이 그림에서는 app.jar를 빌드한다. 

설정 값은 실행 시점 각 환경에 따라 외부에서 주입한다.

   - 개발 서버: app.jar를 실행할 때 dev.db.com값을 외부 설정으로 주입한다.

   - 운영 서버: app.jar를 실행할 때 prod.db.com값을 외부 설정으로 주입한다.

 

cf. 유지보수하기 좋은 애플리케이션 개발의 가장 기본 원칙은 변하는 것과 변하지 않는 것을 분리하는 것이다.

 


 

외부 설정 - 스프링 통합

외부 설정 방법에는 1. 커맨드 라인 옵션 인수 2. 자바 시스템 속성 3. OS 환경변수 모두 외부 설정을 key=value 형식을 사용할 수 있는 방법이다. 하지만 이러한 설정들은 어디에 있는 외부 설정 값을 읽어야 하는지에 따라 각각 읽는 방법이 다르다는 단점이 있다.

외부 설정 값이 어디에 위치하든 상관없이 일관성 있고 편리하게 key=value 형식의 외부 설정 값을 읽을 수 있기 위해 스프링은 EnvironmentPropertySource라는 추상화를 이용한다.

 

 

설정 데이터(파일)인 application.properties, application.ymlPropertySource에 추가되고, Environment를 통해 접근할 수 있다.

 

EnvironmentCheck

package hello;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class EnvironmentCheck {
    private final Environment env;
    public EnvironmentCheck(Environment env) {
        this.env = env;
    }
      
    @PostConstruct
    public void init() {
        String url = env.getProperty("url");
        String username = env.getProperty("username");
        String password = env.getProperty("password");
            log.info("env url={}", url);
            log.info("env username={}", username);
            log.info("env password={}", password);
    } 
}

 

우선 순위

- 더 유연한 것이 우선권을 가진다. (변경하기 어려운 파일보다 실행 시 원하는 값을 줄 수 있는 자바 시스템 속성이 더 우선권을 가진다.)

- 범위가 넓은 것보다 좁은 것이 우선권을 가진다. (자바 시스템 속성은 해당 JVM 안에서 모두 접근할 수 있다. 반면 커맨드 라인 옵션 인수는 main의 arg를 통해서 들어오기 때문에 접근 범위가 더 좁다.)

 


설정 데이터1 - 외부 파일

OS 환경 변수, 자바 시스템 속성, 커맨드 라인 옵션 인수는 사용해야 하는 값이 늘어날 수록 사용하기가 불편해진다.

이를 해결하기 위한 방법이 설정 값을 파일에 넣어서 관리하는 방법이다.

.properties라는 파일은 key=value 형식을 사용해 설정 값을 관리하기 아주 적합하다.

 

application.properties 개발 서버에 있는 외부 파일

url=dev.db.com
username=dev_user
password=dev_pw

 

application.properties 운영 서버에 있는 외부 파일

url=prod.db.com
username=prod_user
password=prod_pw

 

 

설정 데이터2 - 내부 파일 분리

설정 파일을 외부에 관리하는 것은 번거로운 일이다. 이를 해결하기 위한 방법으로 설정 파일을 프로젝트 내부에 포함해 관리하는 것이다.

또한 빌드 시점에 함께 빌드되게 한다. 이렇게 한다면 애플리케이션을 배포할 때 설정 파일의 변경 사항도 함께 배포할 수 있다.

 

1. 프로젝트 안에 소스 코드 뿐 아니라 각 환경에 필요한 설정 데이터도 함께 포함해 관리한다.

   - 개발용 설정 파일: application-dev.properties

   - 운영용 설정 파일: application-prod.properties

2. 빌드 시점에 개발, 운영 설정 파일을 모두 포함해서 빌드한다.

3. 실행할 때 어떤 설정 데이터를 읽어야 할지 최소한의 구분은 필요하다.

   - 개발 환경: application-dev.properties

   - 운영 환경: application-prod.properties

 

application-dev.properties 개발 프로필에서 사용

url=dev.db.com
username=dev_user
password=dev_pw

 

application-prod.properties 운영 프로필에서 사용

url=prod.db.com
username=prod_user
password=prod_pw

 

 

설정 데이터3 - 내부 파일 합체

설정 파일을 각각 분리해서 관리하면 한 눈에 전체가 들어오지 않는 단점이 있다.

이를 해결하기 위해, 스프링은 하나의 파일 안에서 논리적으로 영역을 구분하는 방법을 제공한다.

 

스프링은 하나의 application.properties 파일 안에서 논리적으로 영역을 구분하는 방법을 제공한다

   - application.properties 구분 방법: #---, !---

   - application.yml 구분 방법: ---

 

 

application.properties

spring.config.activate.on-profile=dev
url=dev.db.com
username=dev_user
password=dev_pw
#---
spring.config.activate.on-profile=prod
url=prod.db.com
username=prod_user
password=prod_pw

 

 

기본 값

내 PC에서 개발하는 것을 보통 로컬(local) 개발 환경이라고 한다. 이때 설정 데이터에는 기본 값을 지정할 수 있는데, 프로필 지정과 무관하게 이 값은 항상 사용된다.

 

application.properties

url=local.db.com
username=local_user
password=local_pw
#---
spring.config.activate.on-profile=dev
url=dev.db.com
username=dev_user
password=dev_pw
#---
spring.config.activate.on-profile=prod
url=prod.db.com
username=prod_user
password=prod_pw

 

 

 

YAML

스프링은 설정 데이터를 사용할 때 application.properties 뿐만 아니라 application.yml 이라는 형식도 지원한다.

YAML은 사람이 읽기 좋은 데이터 구조를 목표로 한다. 확장자는 yaml, yml 이고, 주로 yml을 사용한다.

 

 

application.yml 

environment:
  dev:
    url: "https://dev.example.com"
    name: "Developer Setup"
  prod:
    url: "https://another.example.com"
    name: "My Cool App"

 

- YAML의 가장 큰 특징은 사람이 읽기 좋게 계층 구조를 이룬다는 점이다.

- YAML은 space(공백)로 계층 구조를 만든다. space는 1칸을 사용해도 되는데, 보통 2칸을 사용한다.

- 구분 기호로 :를 사용한다. 만약 값이 있다면 key: value : 이후에 공백을 하나 넣고 값을 넣어준다.

 

 


@Profile

 

PayConfig

package hello.pay;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
  
@Slf4j
@Configuration
public class PayConfig {
    
    @Bean
    @Profile("default")
    public LocalPayClient localPayClient() {
        log.info("LocalPayClient 빈 등록");
        return new LocalPayClient();
    }
    
    @Bean
    @Profile("prod")
    public ProdPayClient prodPayClient() {
        log.info("ProdPayClient 빈 등록");
        return new ProdPayClient();
      }
}

 

- @Profile 애노테이션을 사용하면 해당 프로필이 활성화된 경우에만 빈을 등록한다.

- default 프로필(기본값)이 활성화 되어 있으면 LocalPayClient를 빈으로 등록한다.

- prod 프로필이 활성화 되어 있으면 ProdPayClient를 빈으로 등록한다.

 


우선 순위

1. 설정 데이터 (application.properties)

2. OS 환경변수

3. 자바 시스템 속성

4. 커맨드 라인 옵션 인수

5. @TestPropertySource (테스트에서 사용)

 

우선 순위 이해 방법

1. 더 유연한 것이 우선권을 가진다. (변경하기 어려운 파일 보다 실행 시 원하는 값을 줄 수 있는 자바 시스템 속성이 더 우선권을 가진다.)
2. 범위가 넒은 것 보다 좁은 것이 우선권을 가진다.

   - OS 환경변수 보다 자바 시스템 속성이 우선권이 있다.
   - 자바 시스템 속성 보다 커맨드 라인 옵션 인수가 우선권이 있다

 

댓글