이 글은 김영한님의 스프링 부트편 강의중 제목과 관련된 부분을 블로그장의 취향대로 요약한 것이며 강의 자료 및 출처는 가장 아래에서 확인할 수 있습니다.
1. 외부설정을 왜하는가?
스프링부트에서 외부설정을 지원하게된 배경을 아래에서 살펴보자.
1-1. 개발과 운영환경 각각 빌드
같은 코드를 두고 개발 환경과 운영 환경에 빌드를 해야한다면 위와같이 두 번 빌드를해야하는 상황이 올것이다.
두 번 빌드를 한다는것은 문제가 될 수 있다.
만약 추후에 운영 환경에 문제가 생겼을때 개발 환경과 같은 소스코드에서 나온 결과물인지 검증하기가 어렵다.
그래서 보통 아래와 같이 빌드는 한번만 하고 각 환경에 맞추어 실행 시점에 외부 설정값을 주입한다.
* 유지보수하기 좋은 애플리케이션 개발의 기본 원칙은 변하는 것과 변하지 않는 것을 분리하는 것이다.
1-2. 개발과 운영환경 모두 같은 빌드 결과물을 사용
위와같이 같은 빌드 결과물을 가지고 각 환경에따라 외부 설정(ex:db 정보)을 주입하는것이 이상적이다.
따라서 스프링 부트는 위와 같은 외부 설정을 쉽게 하도록 지원해준다.
2.외부 설정의 종류
여기서 외부 설정은 일반적으로 4가지 방법이 있다.
1. OS 환경 변수 : OS에서 지원하는 외부 설정이다. 해당 OS를 사용하는 모든 프로세스에 사용한다.
2. 자바 시스템 속성: 자바에서 지원하는 외부 속성이다. 해당 JVM안에서 사용한다.
3. 자바 커맨드 라인 인수: 커맨드 라인에서 전달하는 외부 설정이다. 실행시 main(args) 메서드에서 사용한다.
4. 외부 파일(설정 데이터) : 프로그램에서 외부 파일을 직접 읽어서 사용한다. 애플리케이션에서 특정 위치의 파일을 읽게해둔다. 예를 들어 data/hello.txt를 읽게 하는식이다.
2-1. OS 환경 변수
해당 OS를 사용하는 모든 프로그램에서 읽을 수 있는 설정값으로 다른 외부 설정과 비교해서 사용범위가 가장 넓다.
하지만 이는 특정 자바 프로그램안에서 사용하기엔 부적절하기에 거의 사용하지 않는다.
2-2. 자바 시스템 속성
JVM 안에서 접근 가능한 외부 설정이다. 아래와 같이 사용가능하다.
java -Durl=dev -jar app.jar // -D 옵션이 -jar 앞에 있음을 주의
-D VM 옵션을 통해서 key=value 형식을 주면 된다.
2-3.커맨드 라인 인수(Command line arguments)
커맨드 라인 인수는 애플리케이션 실행 시점에 외부 설정값을 main(args) 메서드의 args 파라미터로 전달하는 방법이다.
아래와 같이 사용가능하다.
java -jar app.jar dataA dataB
필요한 데이터를 마지막 위치에 스페이스로 구분해서 전달하면 된다.
위 같은 경우 dataA, dataB 2개의 문자가 args에 전달된다.
그런데 어플리케이션을 개발할 때는 보통 key=value 형식으로 데이터를 받는 것이 편리하다.
위 커맨드 라인 인수에 아래와 같이 입력한다면?
java -jar project.jar url=devdb username=dev_user
커맨드 라인 인수는 key=value 형식이 아니기때문에 위 예제는 단순히 문자로 인식된다.
따라서 개발자가 =을 기준으로 직접 데이터를 파싱해서 key=value 형식으로 분리해줘야한다.
* 커맨드 라인 옵션 인수(command line option arguments)
스프링에서는 위같은 불편함을 해소하기 위해 표준 방식을 정의했는데, 그것이 커맨드 라인 옵션 인수이다.
커맨드 라인에 - (dash) 2개를 연결해서 시작하면 key=value 형식으로 정하고 이것을 커맨드 라인 옵션 인수라 한다.
--username=userA --username=userB
참고로 위 인수는 자바 언어의 표준 기능이 아닌 스프링이 제공하는 기능이다.
2-4. 외부 파일
말그대로 외부에 파일을 선언하고 해당 파일을 읽는 방법이다.
3. 스프링의 외부 설정 원리
위 같은 방식은 아래와같은 문제가 발생할 수 있다.
4가지의 외부 설정 방식들은 각각 읽는법이 모두 다르고, 만약 OS에 환경 변수를 뒀는데 추후 정책이 변경되면서 자바 시스템 속성에 환경 변수를 두기로한다면 코드를 모두 변경해야한다.
따라서 스프링은 Environment와 PropertySource 라는 추상화를 통해서 이를 해결한다.
스프링은 로딩 시점에 필요한 PropertySource들을 생성하고, Environment에서 사용할 수 있게 연결해둔다.
쉽게 설명해서 PropertySource는 실제 인수이고, Environment는 조회를 위한 객체이다.
만약 커맨드 라인 옵션 인수와 자바 시스템 속성을 중복해서 설정했다면 어떤것이 먼저일까?
상식 선에서 우선순위는 더 유연한 것이 우선권을 가지고, 범위가 넓은 것 보다 좁은 것이 우선권을 가진다.
즉, JVM 안에서 모두 접근하는것 보다 main의 args를 통해서 들어오는 것이 더 범위가 좁기때문에 커맨드 라인 옵션 인수 설정이 적용된다.
4. 스프링이 제공하는 설정 데이터
실무에선 수십개의 설정값을 사용하기도 하므로 직접 일일이 커맨드 라인 속성, 자바 시스템 속성을 줘서 사용하는것은 힘들다.
따라서 스프링은 application.properties으로 선언된 파일을 자바를 실행하는 위치에 두면 설정 데이터(config data)로 읽어들이는 기능을 제공한다.
위와 같은 설정 데이터를 만들어두면 스프링이 해당 파일을 읽고 PropertySource 구현체를 제공하고 , 이 설정 데이터를 Environment를 통해 조회할수 있다.
5. 내부 파일의 분리
설정 파일을 외부에 두는것은 불편할 수 있다.
서버가 10대일때 변경사항이 있다면, 10대 서버의 설정 파일을 모두 각각 변경해야한다.
따라서 이럴땐 외부 설정을 프로젝트 내부에 포함해서 관리하면 좋을것이다.
개발용 설정 파일을 application-dev.properties로 두고, 운영용 설정 파일을 application-prod.properties로 둔다.
app.jar는 두 설정 파일을 모두 가지고 배포되며, 실행할 때 "프로필"을 이용해서 둘중 하나로 실행하게 된다.
아래와 같은 규칙으로 설정 파일을 생성하면 추후 프로필을 사용해서 맞는 내부 파일을 조회한다.
application-{profile}.properties
즉, 개발서버의 설정 파일은 application-dev.properties가 되고, 운영서버의 설정 파일은 application-prod.properties가
된다.
이후 개발서버의 실행은 커맨드 라인 옵션 인수로 실행한다면 --spring.profiles.active=dev, 자바 시스템 속성으로 실행한다면 -Dspring.profiles.active=dev 와 같이 실행하면된다.
6. 내부 파일의 합체
설정 파일을 분리하게 되면 한눈에 전체가 들어오지 않는다.
따라서 스프링은 이를 보완하기 위해 논리적으로 영역을 구분하는 방법을 제공한다.
간단하게 application.properties안에서 " #--- " 또는 "!---"로 논리적으로 영역을 나눌 수 있다.
프로필에 따라 논리적으로 구분된 설정 데이터를 활성화 하는 방법은
spring.config.active.on-profile에 프로필 값을 지정하면된다.
주의할점은 #--- 주석 위 아래로 주석을 적으면 안되고 정확히 3개의 하이픈 문자가 있어야한다.
이제 실행은 커맨드 라인 옵션 인수로 실행한다면 --spring.profiles.active=dev , 자바 시스템 속성으로 실행한다면 -Dspring.profiles.active=dev로 실행하면 된다.
만약 프로필을 지정하지 않는다면 두가지 모두 읽지 않고 default 프로필이 활성화 되는데 이럴땐 아래와 같이 선언하면된다.
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
가장위에 있는 3줄은 프로필을 설정하지 않았으므로 default 프로필이 된다.
* 출처 자료
'Spring' 카테고리의 다른 글
Spring Advanced 정리 4) 스프링의 프록시 등록 방식 (0) | 2024.03.28 |
---|---|
Spring Advanced 정리 3) 프록시 패턴과 데코레이터 패턴 (0) | 2024.03.26 |
Spring Advanced 정리 2) 템플릿 메서드 패턴과 템플릿 콜백 패턴 (0) | 2024.03.25 |
Spring Advanced 정리 1) 쓰레드 로컬 (0) | 2024.03.14 |
Spring DB 정리 4) 트랜잭션 전파 (2) | 2024.03.13 |