티스토리 뷰

Spring

[Spring] 외부설정과 프로필 2

hyuuny 2023. 4. 3. 01:46

[Spring] 외부설정과 프로필 1


외부 설정 - 커맨드 라인 옵션 인수와 스프링 부트

스프링 부트는 커맨드 라인을 포함해서 커맨드 라인 옵션 인수를 활용할 수 있는 ApplicationArguments를 스프링 빈으로 등록해둔다. 그리고 그 안에 입력한 커맨드 라인을 저장해둔다. 그래서 해당 빈을 주입 받으면 커맨드 라인으로 입력한 값을 어디서든 사용할 수 있다.


CommandLineBean

@Slf4j
@RequiredArgsConstructor
@Component
public class CommandLineBean {

    private final ApplicationArguments arguments;

    @PostConstruct
    public void init() {
        log.info("source {}", List.of(this.arguments.getSourceArgs()));
        log.info("optionNames {}", List.of(this.arguments.getOptionNames()));
        Set<String> optionNames = this.arguments.getOptionNames();
        optionNames
                .forEach(name -> log.info("option args {}={}", name, arguments.getOptionValues(name)));
    }

}
  • 파일은 src/main 하위에 위치한다.

커맨드 라인 인수에 --url=devdb --username=hyuuny --password=dev_pw를 입력하고, 실행한다.


실행 결과

실행 결과를 보면, 입력한 커맨드 라인 인수, 커맨드 라인 옵션 인수를 확인할 수 있다.


외부 설정 - 스프링 통합

지금까지 살펴본, 커맨드 라인 옵션 인수, 자바 시스템 속성, OS 환경변수는 모두 외부 설정을 key=value 형식으로 사용할 수 있는 방법이다. 그런데 이 외부 설정값을 읽어서 사용하는 개발자 입장에서 단순하게 생각해보면, 모두 key=value 형식이고, 설정값을 외부로 뽑아둔 것이다. 그런데 어디에 있는 외부 설정값을 읽어야 하는지에 따라서 각각 읽는 방법이 다르다는 단점이 있다.
예를 들어서 OS 환경 변수에 두면 System.getenv(key)를 사용해야 하고, 자바 시스템 속성을 사용하면 System.getProperty(key)를 사용해야 한다. 만약 OS에 환경 변수를 두었는데, 이후에 정책이 변경되어서 자바 시스템 속성에 환경 변수를 두기로 했다고 가정해보자. 그러면 해당 코드들을 모두 변경해야 한다.


외부 설정값이 어디에 위치하든 상관없이 일관성 있고, 편리하게 key=value 형식의 외부 설정값을 읽을 수 있으면 사용하는 개발자 입장에서 더 편리하고 또 외부 설정값을 설정하는 방법도 더 유연해질 수 있다. 예를 들어서 외부 설정값을 OS 환경변수를 사용하다가 자바 시스템 속성으로 변경하는 경우에 소스코드를 다시 빌드하지 않고 그대로 사용할 수 있다.


스프링은 이 문제를 EnvironmentPropertySource라는 추상화를 통해서 해결한다.


스프링 외부 설정 통합

PropertySource

  • org.springframework.core.env.PropertySource
  • 스프링은 PropertySource라는 추상 클래스를 제공하고, 각각의 외부 설정를 조회하는 XxxPropertySource 구현체를 만들어두었다.
    • ex) CommandLinePropertySource, SystemEnvironmentPropertySource
  • 스프링은 로딩 시점에 필요한 PropertySource들을 생성하고, Environment에서 사용할 수 있게 연결해둔다.

Environment

  • org.springframework.core.env.Environment
  • Environment를 통해서 특정 외부 설정에 종속되지 않고, 일관성 있게 key=value 형식의 외부 설정에 접근할 수 있다.
    • environment.getProperty(key)를 통해서 값을 조회할 수 있다.
    • Environment는 내부에서 여러 과정을 거쳐서 PropertySource들에 접근한다.
    • 같은 값이 있을 경우를 대비해서 스프링은 미리 우선순위를 정해두었다.
  • 모든 외부 설정은 이제 Environment를 통해서 조회하면 된다.

설정 데이터(파일)

application.properties, application.ymlPropertySource에 추가되기 때문에 Environment를 통해서 접근할 수 있다.


우선 순위

  • 커맨드 라인 옵션 인수: --url=proddb --username=hyuuny --password=prod_pw
  • 자바 시스템 속성: -Durl=devdb -Dusername=hyuuny -Dpassword=dev_pw

실행 결과

우선순위는 2가지만 기억하면 된다.

  • 더 유연한 것이 우선권을 가진다. (변경하기 어려운 파일 보다 실행시 원하는 값을 줄 수 있는 자바 시스템 속성이 더 우선권을 가진다.)
  • 범위가 넒은 것 보다 좁은 것이 우선권을 가진다. (자바 시스템 속성은 해당 JVM 안에서 모두 접근할 수있다. 반면에 커맨드 라인 옵션 인수는 main의 arg를 통해서 들어오기 때문에 접근 범위가 더 좁다.)

자바 시스템 속성과 커맨드 라인 옵션 인수의 경우 커맨드 라인 옵션 인수의 범위가 더 좁기 때문에 커맨드 라인 옵션 인수가 우선권을 가진다.


지금까지 살펴본 OS 환경 변수, 자바 시스템 속성, 커맨드 라인 옵션 인수는 사용해야 하는 값이 늘어날수록 사용하기가 불편해진다. 실무에서는 수십개의 설정값을 사용하기도 하므로 이런 값들을 프로그램을 실행할 때 마다 입력하게 되면 번거롭고, 관리도 어렵다.


그래서 등장하는 대안으로는 설정값을 파일에 넣어서 관리하는 방법인데, 애플리케이션 로딩 시점에 해당 파일을 읽어들이면 된다. 그 중에서도 .properties라는 파일은 key=value 형식을 사용해서 설정값을 관리하기에 아주 적합하다.



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

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

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

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

예를 들면 개발 서버와 운영 서버 각각에 application.properties라는 같은 이름의 파일을 준비해둔다. 그리고 애플리케이션 로딩 시점에 해당 파일을 읽어서 그 속에 있는 값들을 외부 설정값으로 사용하면 된다.


스프링과 설정 데이터

개발자는 application.properties라는 이름의 파일을 자바를 실행하는 위치에 만들어 두기만 하면 된다. 그러면 스프링이 해당 파일을 읽어서 사용할 수 있는 PropertySource의 구현체를 제공한다. 스프링에서는 이러한 application.properties 파일을 설정 데이터(Config data) 라 하며, 설정 데이터도 Environment를 통해서 조회할 수 있다.


  • yml 형식의 application.yml에도 동일하게 적용된다

하지만 외부 설정을 별도의 파일로 관리하게 되면 설정 파일 자체를 관리하기 번거로운 문제가 발생한다. 만약 서버가 10대면 변경사항이 있을 때 10대 서버의 설정 파일을 모두 각각 변경해야 하는 불편함이 있다. 설정 파일이 별도로 관리되기 때문에 설정값의 변경 이력을 확인하기 어렵다. 특히 설정값의 변경 이력이 프로젝트 코드들과 어떻게 영향을 주고 받는지 그 이력을 같이 확인하기 어렵다.


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

설정 파일을 외부에 관리하는 것은 상당히 번거로운 일이다. 설정을 변경할 때 마다 서버에 들어가서 각각의 변경 사항을 수정해두어야 한다.


이 문제를 해결하는 간단한 방법은 설정 파일을 프로젝트 내부에 포함해서 빌드 시점에 함께 빌드되게 하는 것이다. 이렇게 하면 애플리케이션을 배포할 때 설정 파일의 변경 사항도 함께 배포할 수 있다. 쉽게 이야기해서 jar 하나로 설정 데이터까지 포함해서 관리하는 것이다.


  • 프로젝트 안에 소스 코드 뿐만 아니라 각 환경에 필요한 설정 데이터도 함께 포함해서 관리한다.
    • 개발용 설정 파일: application-dev.properties
    • 운영용 설정 파일: application-prod.properties
  • 빌드 시점에 개발, 운영 설정 파일을 모두 포함해서 빌드한다.
  • app.jar는 개발, 운영 두 설정 파일을 모두 가지고 배포된다.
  • 실행할 때 어떤 설정 데이터를 읽어야 할지 최소한의 구분은 필요하다.
    • 개발 환경이라면 application-dev.properties를 읽어야 하고,
    • 운영 환경이라면 application-prod.properties를 읽어야 한다.

외부 설정으로 넘어온 프로필 값이 dev라면 application-dev.properties를 읽고 prod라면 application-prod.properties를 읽어서 사용하면 된다. 스프링은 이미 설정 데이터를 내부에 파일로 분리해두고 외부 설정값(프로필)에 따라 각각 다른 파일을 읽는 방법을 다 구현해두었다.


프로필

스프링은 프로필이라는 개념을 지원한다. spring.profiles.active 외부 설정에 값을 넣으면 해당 프로필을 사용한다고 판단한다. 그리고 프로필에 따라서 다음과 같은 규칙으로 해당 프로필에 맞는 내부 파일(설정 데이터)을 조회한다.

  • application-{profile}.properties
  • spring.profiles.active=dev
    • dev 프로필이 활성화 되었다.
    • application-dev.properties를 설정 데이터로 사용한다.
  • spring.profiles.active=prod
    • prod 프로필이 활성화 되었다.
    • application-prod.properties를 설정 데이터로 사용한다.

application-dev.properties

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

profile 옵션에 dev 추가

실행 결과


application-prod.properties

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

profile 옵션에 prod 추가

실행 결과


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

설정 파일을 각각 분리해서 관리하면 한눈에 전체가 들어오지 않는 단점이 있다. 스프링은 이런 단점을 보완하기 위해 물리적인 하나의 파일 안에서 논리적으로 영역을 구분하는 방법을 제공한다.

  • 기존에는 dev 환경은 application-dev.properties, prod 환경은 application-prod.properties 파일이 필요했다.
  • 스프링은 하나의 application.properties 파일 안에서 논리적으로 영역을 구분하는 방법을 제공한다.
  • application.properties 라는 하나의 파일 안에서 논리적으로 영역을 나눌 수 있다.
    • application.properties 구분 방법: #--- 또는 !--- (dash 3)
    • application.yml 구분 방법: --- (dash 3)
  • 그림의 오른쪽 application.properties는 하나의 파일이지만 내부에 2개의 논리 문서로 구분되어 있다.
    • dev 프로필이 활성화 되면 상위 설정 데이터가 사용된다.
    • prod 프로필이 활성화 되면 하위 설정 데이터가 사용된다.
  • 프로필에 따라 논리적으로 구분된 설정 데이터를 활성화 하는 방법
    • spring.config.activate.on-profile에 프로필 값 지정

application.properties

url=local.db.com
username=local_hyuuny
password=local_pw
#---
spring.config.activate.on-profile=dev
url=dev.db.com
username=dev_hyuuny
password=dev_pw
#---
spring.config.activate.on-profile=prod
url=prod.db.com
username=prod_hyuuny
password=prod_pw

설정 데이터 적용 순서

스프링은 단순하게 문서를 위에서 아래로 순서대로 읽으면서 사용할 값을 설정한다.


스프링은 순서상 위에 있는 local 관련 논리 문서의 데이터들을 읽어서 설정한다. 여기에는 spring.config.activate.on-profile와 같은 별도의 프로필을 지정하지 않았기 때문에 프로필과 무관하게 항상 값을 사용하도록 설정한다.

url=local.db.com
username=local_hyuuny
password=local_pw

스프링은 그 다음 순서로 dev 관련 논리 문서를 읽는데 만약 dev 프로필이 설정되어있다면, 기존 데이터를 dev 관련 논리 문서의 값으로 대체한다. 물론 dev 프로필을 사용하지 않는다면 dev 관련 논리 문서는 무시되고, 그 값도 사용하지 않는다.

url=local.db.com -> dev.db.com
username=local_hyuuny -> dev_hyuuny
password=local_pw -> dev_pw

스프링은 그 다음 순서로 prod 관련 논리 문서를 읽는데 만약 prod 프로필이 설정되어있다면, 기존 데이터를 prod 관련 논리 문서의 값으로 대체한다. 물론 prod 프로필을 사용하지 않는다면 prod 관련 논리 문서는 무시되고, 그 값도 사용하지 않는다.

url=local.db.com -> prod.db.com
username=local_hyuuny -> prod_hyuuny
password=local_pw -> prod_pw

프로필을 한번에 둘 이상 설정하는 것도 가능하다.

  • --spring.profiles.active=dev,prod

이렇게 우선순위에 따라서 설정을 추가하거나 변경하는 방식은 상당히 편리하면서도 유연한 구조를 만들어준다. 실무에서 대부분은 applicaiton.properties에 외부 설정값들을 보관한다. 이렇게 설정 데이터를 기본으로 사용하다가 일부 속성을 변경할 필요가 있다면 더 높은 우선순위를 가지는 자바 시스템 속성이나 커맨드 라인 옵션 인수를 사용하면 되는 것이다.


또는 기본적으로 application.properties를 jar 내부에 내장하고 있다가, 특별한 환경에서는 application.properties를 외부 파일로 새로 만들고 변경하고 싶은 일부 속성만 입력해서 변경하는 것도 가능하다.




김영한. 스프링 부트 - 핵심 원리와 활용. 인프런.

'Spring' 카테고리의 다른 글

[Spring] YAML , @Profile  (0) 2023.04.09
[Spring] 외부 설정 방법  (0) 2023.04.06
[Spring] 외부설정과 프로필 1  (0) 2023.04.02
[Spring] build.gradle 라이브러리 관리  (0) 2023.03.13
[Spring] 스프링 부트 내장 톰캣  (0) 2023.03.12
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함