외부설정이란
하나의 애플리케이션을 여러 다른 환경에서 사용해야 할 때가 있습니다.
개발환경, 운영환경에 따라 URL, DB 경로등을 다양하게 설정해야 하기 때문에 외부 설정이 필요합니다.
그래서 개발용 app.jar, 운영용 app.jar 파일을 설정하는 것이 아니라 하나의 app.jar 를 개발하고 배포한 뒤에 각 환경에 맞추어 실행 시점에 외부 설정값을 주입하면 한번만 빌드해도 되고, 개발버전과 운영버전의 빌드 결과물이 같기 때문에 개발환경에서 검증되면 운영 환경에서도 믿고 사용할 수가 있습니다.
유지보수하기 좋은 애플리케이션 개발의 가장 큰 기본 원칙은 변하는 것과 변하지 않는 것을 분리하는 것입니다.
외부설정방법
외부 설정을 하는 방법은 일반적으로 다음 4가지 방법이 있습니다.
1. OS 환경변수
2. 자바 시스템 속성
3. 자바 커맨드 라인 인수
4. 외부파일(설정 데이터)
OS 환경변수
OS 에서 지원하는 외부 설정, 해당 OS 를 사용하는 모든 프로세스에서 사용
해당 OS 를 사용하는 모든 프로그램에서 읽을 수 있는 설정 값입니다.
윈도우 OS 는 set 을 사용하고, Mac 또는 리눅스는 printenv 를 사용합니다.
간단하게 printenv 파일 내용을 보면 아래와 같은 기본 설정값들이 들어가 있습니다.
LANG=ko_KR.UTF-8
TERM=xterm-256color
OS 환경변수의 값을 설정하는 방법은 구글링에 자세히 나와있습니다.
구글링으로 찾는걸 추천하는 이유는 잘 사용하지 않기 때문입니다.
스프링에서 OS 환경변수들을 가져오려면 아래와 같이 코드를 짜주시면 됩니다.
public class OsEnv {
public static void main(String[] args) {
Map<String, String> envMap = System.getenv();
}
}
System.getenv() 는 전체 OS 환경변수를 Map 으로 조회를 해줍니다.
하지만 OS 환경변수는 다양한 프로그램에서 공유되는 값이기 때문에 잘못하면 오류가 발생하기 쉽습니다.
따라서 자바프로그램 안에서만 사용하는 방법을 주로 사용합니다.
자바 시스템 속성
자바에서 지원하는 외부설정, 해당 JVM 안에서 사용
실행한 JVM 안에서 접근 가능한 외부 설정입니다.
자바 시스템 속성은 다음과 같이 자바 프로그램을 실행할 때 사용됩니다.
java -Durl=dev -jar app.jar
-D VM 옵션을 통해 key=value 형식을 주면 됩니다.
주의해야 할 점은 -D 옵션은 -jar 보다 앞에 있어야 합니다.
우선 실행할 때 자바 시스템 속성을 추가해 주어야 합니다.
인텔리제이를 사용한다고 가정하면 Run/Debug Configurations 설정에서 VM options 에서 -Durl=devdb -Dusername=dev_user 라고 설정해주면 됩니다.
아래는 자바 시스템 속성을 꺼개는 예시 코드입니다.
// 전부 꺼내오기
Properties properties = System.getProperties();
// 특정 값 꺼내오기
String url = System.getProperties("url")
//...
만약 jar 로 미리 빌드되어 있다면 실행시 다음과 같이 자바 시스템 속성을 추가할 수 있습니다.
java -Durl=devdb -Dusername=dev_user -jar app.jar
이렇게 설정하면 똑같이 자바시스템 속성이 추가가 됩니다.
자바 커맨드 라인 인수
커맨드 라인에서 전달하는 외부 설정, 실행 시 main(args) 메서드에서 사용
사용법은 아래와 같습니다.
java -jar app.jar dataA dataB
public class CommandLineV1 {
public static void main(String[] args) {
for(String arg: args) {
log.info("args {}", args);
}
}
}
이렇게 설정을 하면 dataA, dataB 가 출력이 됩니다.
하지만 커맨드 라인 인수의 단점은 java -jar app.jar url=dev.com 이라고 설정을 하면, key=value 로 분리되지 않고
단순히 "url=dev.com" 이라는 문자열을 반환하게 됩니다.
따라서 아래와 같이 추가적인 작업이 필요합니다.
--url=dev.com --password=123
스프링은 커맨드 라인에 -- 를 연결해서 시작하면 key=value 형태로 반환하게 해줍니다.
이것을 커맨드 라인 옵션 인수라고 합니다.
이렇게 설정을 하면 스프링 부트는 커맨드 라인을 포함해서 커맨드 라인 옵션 인수를 활용할 수 있는
ApplicationArguments 를 스프링 빈으로 등록을 해줍니다.
이걸 이용해서 값을 꺼내오면 됩니다.
위와 같은 3가지 방법의 단점
앞서 말한 3가지 방법들은 어떤 방법으로 외부설정값을 읽어야 하는지 방법이 다 다르다는 것입니다.
OS 환경변수는 System.getenv() 이고, 자바시스템속성은 System.getProperties() 를 사용해야 합니다.
만약 정책이 변경되서 OS 환경변수를 사용하는 프로그램이 자바시스템 속성으로 변경된다면 코드를 하나하나 다 고쳐야 하는 비용이 발생하게 됩니다.
스프링은 이러한 문제를 해결하기 위해 Enviroment, PropertySource 라는 추상화를 통해 해결해줍니다.
@Slf4j
@Component
@RequiredArgsConstructor
public class EnviromentCheck {
private final Enviroment env;
@PostConstruct
public void init() {
String url = env.getProperty("url");
String name = env.getProperty("username");
//...
}
}
커맨드 라인 옵션 인수 실행
--url=devdb --username=dev_user
자바 시스템 속성 실행
-Durl=devdb -Dusername=dev_user
이렇게 커맨드 라인 옵션 인수를 실행하거나, 자바 시스템 속성을 실행해도 오류가 발생하지 않고 동일한 결과를 반환해 줍니다.
하지만 이러한 방법들도 설정값이 많아지면 관리하기가 너무 힘들어집니다.
따라서 .properties 라는 파일을 이용해서 애플리케이션 로딩 시점에 해당 파일을 읽어들일 수 있는 방법을 제공해줍니다.
외부파일(설정데이터)
프로그램에서 외부 파일을 직접 읽어서 사용합니다.
간단하게 properties, yml 을 생가하시면 됩니다.
현재 예시는 설정파일을 외부에서 관리합니다.
app.jar -> 배포 -> app.jar 에서 application.properties 를 참조해서 실행
application.properties
url=dev.db.com
username=chan
//...
동작을 확인하려면 아래와 같은 작업이 필요합니다.
./gradlew clean build -> build/libs 이동하고 해당 위치에 application.properties 파일 생성
java -jar external-0.0.1-SNAPSHOT.jar 실행
1차적으로는 문제점이 해결되지만 여전히 남아있는 문제점이 있습니다.
서버가 10대일때 .properties 에 변경사항이 있으면 10번의 수정이 필요하고 결국 변경이력도 확인하기 어렵다는 문제입니다.
이렇게 설정파일을 외부에 관리하는 것은 상당히 번거로운 일입니다.
설정을 변경할 때마다 서버에 들어가서 각각의 변경 사항을 수정해야 하기 때문입니다.
이 문제를 해결하는 간단한 방법은 설정 파일을 프로젝트 내부에 포함해서 관리하는 것입니다.
그리고 빌드 시점에 함께 빌드하는 것입니다.
application-{}.properties
application-dev.properties
application-prod.properties
빌드 시점에 개발, 운영 설정 파일을 모두 포함해서 빌드합니다.
app.jar 는 개발, 운영 두 설정 파일을 모두 가지고 배포합니다.
하지만 이렇게만 설정하면 실행할 때 어떤 설정(dev, prod) 데이터를 읽어야 하는지 구분이 필요합니다.
dev 프로필로 설정하면 application-dev 를 실행하고, prod 프로필을 설정하면 application-prod 가 실행되어야 합니다.
고맙게도 스프링은 이러한 프로필 설정도 지원을 해줍니다.
spring.profiles.active 외부설정에 값을 넣으면 해당 프로필을 사용한다고 스프링은 판단합니다.
그리고 프로필에 따라 아래와 같은 규칙으로 해당 프로필에 맞는 내부 설정파일(설정 데이터) 를 조회합니다.
application-{profile}.properties
spring-profiles.active=dev -> dev.properties 활성화
IDE 에서 커맨드 라인 옵션 인수를 --spring.profiles.active=dev 로 설정하면 되고,
자바시스템 속성은 -Dspring.profiles.active=dev 로 설정하시면 됩니다.
마지막으로 아래와 같이 실행하면 정상적으로 동작하는 것을 확인하실 수 있습니다.
./gradlew clean build
build/libs 로 이동 -> java -Dspring.profiles.active=dev -jar external-0.0.1-SNAPSHOT.jar
이제 설정데이터를 프로젝트 안에서 함께 관리할 수 있게 되었고, 배포 시점에 설정 정보도 함께 배포할 수 있게 되었습니다.
그렇지만 정말 마지막으로 남은 문제가 하나 있습니다.
설정 파일을 각각 분리해서 관리하면 한눈에 전체가 들어오지 않는다는 단점입니다.
내부파일 합체
스프링에서는 dev, prod 같이 분리한 파일을 한번에 관리해줄 수 있게 도와줍니다.
application.properties
spring.config.active.on-profile=dev
url=devDb
username=dev_user
password=dev_pw
#---
spring.config.active.on-profile=prod
url=prodDb
username=prod_user
password=prod_pw
주의해야 할 점은 application.properties 에서 #--- 또는 !--- 로 구분해야합니다.
혹시나 yml 을 사용하시는 분들은 --- 으로 구분하시면 됩니다.
아래와 같이 실행하면 기존의 application-prod, application-dev 파일로 설정한 부분과 다를것 없이
실행되는 모습을 보실 수 있습니다.
커멘드 라인 옵션 인수 : --spring.profiles.active=dev
자바 시스템 속성 : -Dspring.profiles.active=dev
내부파일의 기본값
만약 개발자의 실수로 자바 시스템속성, 커맨드 라인 옵션 인수등을 실행하지 않거나 적어놓지 않으면 어떻게 동작할까요??
실행결과를 보면 다 NULL 이 반환되게 됩니다. 그리고 첫줄에 활성 프로필이 없어서 default 라는 이름의 프로필이 활성화됩니다.
스프링은 이러한 실수를 방지하기 위해 default 기본 옵션을 지원해줍니다.
또한 내 PC 에서 개발하는 것을 보통 로컬(local) 개발환경이라고 하는데, 이때도 항상 프로필을 지정하면서 실행하는 것은 상당히 피곤하기 때문에 default 기능을 사용하시면 됩니다.
application.properties
url=localDB
username=local_user
password=local_pw
#---
spring.config.active.on-profile=dev
url=devDb
username=dev_user
password=dev_pw
#---
spring.config.active.on-profile=prod
url=prodDb
username=prod_user
password=prod_pw
이렇게 설정을 하시면 스프링은 문서를 위에서 아래로 순서대로 읽으면서 설정을 해줍니다.
설정값이 없다면 맨 위에 default 로 설정한 값이 출력이 됩니다.
만약 프로필 설정을 해주면 프로필이 default 보다 우선권을 가지게 됩니다.
'Spring' 카테고리의 다른 글
Swagger (0) | 2025.10.02 |
---|---|
WAR 배포 및 분석 (0) | 2025.09.25 |
JPA 의 OSIV (1) | 2025.09.11 |
JPA 에 대하여 (8) | 2025.08.25 |
Spring 에서 CORS 설정 (3) | 2025.07.09 |