[Spring Boot] Properties 외부화: PropertySource, Profile, @ConfigurationProperties
정의
Spring Boot 는 설정값을 15가지 소스에서 우선순위로 병합. 같은 키가 여러 곳에 있으면 우선순위 높은 게 이김. 코드 변경 없이 환경별 설정 가능.
핵심 소스 (우선순위 높은 순):
- Devtools 글로벌 설정
~/.config/spring-boot/ @TestPropertySource(테스트)SPRING_APPLICATION_JSON(환경변수)- Command-line arguments (
--server.port=9090) - OS 환경변수 (
SERVER_PORT=9090) application-{profile}.yml(외부 → jar 안)application.yml(외부 → jar 안)@PropertySource어노테이션- default 값 (
@Value("${x:fallback}"))
높은 우선순위 = 운영 환경에서 override 쉬움 패턴.
application.yml vs properties
# application.yml (선호: 계층 표현 명확)
spring:
datasource:
url: jdbc:postgresql://localhost/myapp
username: app
server:
port: 8080
servlet:
context-path: /api
# application.properties (단순)
spring.datasource.url=jdbc:postgresql://localhost/myapp
spring.datasource.username=app
server.port=8080
server.servlet.context-path=/api
같은 폴더에 둘 다 있으면 properties 가 우선. 보통 하나만 사용.
Profile-Specific 설정
application-{profile}.yml 명명 규칙:
src/main/resources/
├── application.yml # 공통
├── application-dev.yml # dev profile 활성 시
├── application-prod.yml # prod profile 활성 시
└── application-local.yml # 로컬 개발
활성화 방법:
# 1) JVM 인자
java -jar app.jar --spring.profiles.active=prod
# 2) 환경변수
SPRING_PROFILES_ACTIVE=prod java -jar app.jar
# 3) application.yml 안에서
spring:
profiles:
active: prod
여러 profile 동시: dev,debug 콤마 구분.
YAML 멀티 문서 (Spring Boot 2.4+)
한 파일 안에 profile 별 섹션:
spring:
application:
name: myapp
server:
port: 8080
---
spring:
config:
activate:
on-profile: prod
server:
port: 9090
spring:
datasource:
url: jdbc:postgresql://prod-db/myapp
---
spring:
config:
activate:
on-profile: dev
server:
port: 8080
spring:
datasource:
url: jdbc:h2:mem:dev
--- 로 구분, spring.config.activate.on-profile 로 조건. 한 파일에 모아두는 데 유용.
@ConfigurationProperties (타입 안전 바인딩)
@ConfigurationProperties(prefix = "app.mail")
@ConstructorBinding // record / 불변
public record MailProperties(
String host,
int port,
String username,
String password,
Duration timeout,
Tls tls,
List<String> recipients
) {
public record Tls(boolean enabled, String protocol) {}
}
@SpringBootApplication
@EnableConfigurationProperties(MailProperties.class)
class App { ... }
app:
mail:
host: smtp.example.com
port: 587
username: ${MAIL_USER}
password: ${MAIL_PASSWORD}
timeout: 5s # Duration 자동 파싱
tls:
enabled: true
protocol: TLSv1.3
recipients:
- alice@example.com
- bob@example.com
@Value 대비:
- 타입 검증 (compile 타임)
- IDE 자동완성 (spring-boot-configuration-processor 추가 시)
- @Validated 와 조합 시 startup 시점 검증
- 불변 (record 권장)
Relaxed binding
같은 property 를 여러 표기로:
app.mail.timeout-seconds # kebab-case (yml 표준)
APP_MAIL_TIMEOUT_SECONDS # env var (uppercase + underscore)
app.mail.timeoutSeconds # camelCase
app.mail.timeout_seconds # snake_case
모두 같은 키로 인식. 환경변수 (APP_MAIL_HOST) ↔ yml (app.mail.host) 자동 매핑.
@Value (단순 사용)
@Service
class GreetingService {
@Value("${app.greeting:Hello}")
private String greeting;
@Value("${app.recipients}")
private List<String> recipients; // 콤마 구분 자동 파싱
@Value("${app.timeout:5s}")
private Duration timeout;
}
: 뒤 default. 없으면 startup 실패.
복잡한 구조나 nested 필드면 @ConfigurationProperties 권장. @Value 는 단발성 simple value 만.
SpEL 확장
@Value("#{T(java.lang.Math).max(1024, ${app.min-pool-size:512})}")
int poolSize;
@Value("#{systemProperties['user.timezone'] ?: 'UTC'}")
String timezone;
복잡한 식 사용 가능. 가독성 떨어지므로 자제.
환경변수 매핑
OS env var → property:
SPRING_DATASOURCE_URL → spring.datasource.url
APP_MAIL_HOST → app.mail.host
APP_MAIL_TLS_PROTOCOL → app.mail.tls.protocol
APP_RECIPIENTS_0 → app.recipients[0] (list index)
APP_RECIPIENTS_1 → app.recipients[1]
Container / K8s 환경에서 표준. ConfigMap / Secret 을 env var 로 mount.
SPRING_APPLICATION_JSON
JSON 한 줄로 여러 property 주입:
SPRING_APPLICATION_JSON='{"server":{"port":9090},"spring":{"profiles":{"active":"prod"}}}' \
java -jar app.jar
Heroku, Cloud Foundry 같은 PaaS 에서 자주 사용.
Command-line override
java -jar app.jar \
--server.port=9090 \
--spring.profiles.active=prod \
--logging.level.root=WARN
긴급 운영 변경에 유용.
외부 파일 로드
# JAR 옆 application.yml 우선 (재배포 없이 변경)
java -jar app.jar --spring.config.location=classpath:/,file:./config/
# 또는 단일 파일
java -jar app.jar --spring.config.location=file:/etc/myapp/application.yml
K8s ConfigMap mount 패턴.
Spring Cloud Config
원격 설정 저장소 (Git, Vault, Consul) 통합:
spring:
config:
import: "configserver:http://config-server:8888"
여러 인스턴스 가 같은 설정 공유. spring-cloud 참고.
검증 (@Validated)
@ConfigurationProperties(prefix = "app.mail")
@Validated
public record MailProperties(
@NotBlank String host,
@Min(1) @Max(65535) int port,
@NotEmpty List<@Email String> recipients
) {}
startup 시점에 검증. 잘못된 설정 = 즉시 실패 (운영 환경에서 critical).
자주 보는 패턴
시나리오 1: dev/prod 분리
# application.yml (공통)
spring:
application:
name: myapp
# application-dev.yml
spring:
datasource:
url: jdbc:h2:mem:dev
jpa:
show-sql: true
hibernate:
ddl-auto: create-drop
# application-prod.yml
spring:
datasource:
url: ${DB_URL}
username: ${DB_USER}
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
logging:
level:
root: WARN
시나리오 2: K8s ConfigMap + Secret
apiVersion: v1
kind: ConfigMap
data:
application.yml: |
spring:
profiles:
active: prod
server:
port: 8080
---
apiVersion: v1
kind: Secret
data:
DB_PASSWORD: <base64>
Pod env var 로 mount + --spring.config.location 으로 ConfigMap 파일 마운트.
시나리오 3: 외부 비밀번호 (Vault)
spring:
config:
import: "vault://"
cloud:
vault:
authentication: TOKEN
token: ${VAULT_TOKEN}
uri: https://vault.internal
비밀번호 / API 키 분리.
함정과 베스트 프랙티스
- 운영 비밀번호는 git 에 절대 commit 금지:
${ENV_VAR}또는 Vault @ConfigurationProperties권장:@Value는 단순한 것만@Validated로 startup 시점 검증: 운영 실수 조기 감지- Duration / DataSize 표기 활용:
5s,1m,10MB,1GiB자동 파싱 - profile 별 파일 분리 vs 멀티 문서 YAML: 팀 컨벤션 정하기
spring.config.import사용: Vault, Consul, Cloud Config 같은 외부 소스application.yml의 environment-specific 값 → env var override: 12-factor 원칙spring-boot-configuration-processor추가: IDE 자동완성 + IntelliJ 의 설정 키 검증
관련 위키
이 글의 용어 (5개)
- [Spring Boot] 자동 구성과 @SpringBootApplicationspring
- 정의 Spring Boot의 핵심 가치 = 자동 구성(autoconfiguration). classpath의 라이브러리를 보고 합리적 기본 설정으로 Bean 등록. Tomcat이…
- [Spring Cloud] Eureka, Config, Gateway, OpenFeignspring
- 정의 Spring Cloud는 Spring Boot 기반 마이크로서비스 인프라 패턴 (service discovery, config server, gateway, circuit …
- [Spring] @Conditional, Profile, @ConfigurationPropertiesspring
- 정의 Spring Boot는 조건부 Bean 등록 메커니즘을 제공한다. classpath, property, 다른 Bean 유무 등에 따라 자동 구성을 활성화/비활성화. , 어노…
- [Spring] Bean Validation: @Valid, @NotBlank, customspring
- 정의 Spring은 Jakarta Bean Validation (JSR-380)을 표준으로 사용. , , 등 어노테이션으로 선언적 검증. Spring MVC가 로 자동 통합. 설…
- [Spring] IoC와 DI: Bean, ApplicationContext, @Autowiredspring
- 정의 IoC (Inversion of Control)는 객체 생성/생명주기 제어를 프레임워크가 가져가는 원칙. DI (Dependency Injection)는 그 구현 방법. S…
💬 댓글