Spring Boot @ConfigurationProperties 검증: 잘못된 운영 설정을 시작 단계에서 차단하기
결제 서버 주소가 비어 있거나 재시도 횟수에 음수가 들어갔는데도 애플리케이션이 정상적으로 시작된다면, 오류는 실제 요청이 들어온 뒤에야 드러납니다. 배포는 성공한 것처럼 보이지만 첫 결제에서 장애가 발생하는 구조입니다.
Spring Boot의 @ConfigurationProperties와 Jakarta Validation을 함께 사용하면 잘못된 설정을 애플리케이션 시작 단계에서 차단할 수 있습니다. 운영자가 수정해야 할 값과 실패 원인도 시작 로그에서 바로 확인할 수 있습니다.
@ConfigurationProperties가 필요한 이유
Spring Boot 설정값은 YAML, properties 파일, 환경 변수, 명령행 인수 등 여러 위치에서 들어옵니다. @Value로 하나씩 주입할 수도 있지만, 관련 설정이 늘어나면 흩어진 문자열 키를 관리하기 어렵습니다.
@Value("${payment.base-url}")
private String baseUrl;
@Value("${payment.timeout}")
private Duration timeout;
@ConfigurationProperties는 같은 접두사의 값을 하나의 타입 안전한 객체로 묶습니다.
| 기준 | @Value |
@ConfigurationProperties |
|---|---|---|
| 적합한 용도 | 단일 값, 간단한 표현식 | 서비스별 구조화된 설정 |
| 타입 변환 | 지원 | 지원 |
| 여러 값 탐색 | 필드마다 키 확인 | 접두사 기준으로 한곳에 모임 |
| 유효성 검증 | 별도 구성 필요 | @Validated와 자연스럽게 결합 |
| 불변 객체 | 작성이 번거로움 | record와 잘 맞음 |
검증 의존성 추가
Bean Validation 구현을 사용할 수 있도록 다음 의존성을 추가합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
설정 파일 작성
결제 연동에 필요한 값을 payment 아래에 모아 보겠습니다.
payment:
base-url: https://sandbox-payment.example.com
timeout: 3s
max-retries: 2
Spring Boot의 완화된 바인딩 덕분에 base-url은 Java의 baseUrl, max-retries는 maxRetries에 연결됩니다. 3s는 Duration으로 변환됩니다.
record로 바인딩하고 검증하기
package com.example.payment;
import java.time.Duration;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@Validated
@ConfigurationProperties(
prefix = "payment",
ignoreUnknownFields = false
)
public record PaymentProperties(
@NotBlank String baseUrl,
@NotNull Duration timeout,
@NotNull @Min(0) @Max(5) Integer maxRetries
) {
}
@Validated가 있어야 바인딩된 객체에 검증이 실행됩니다. @NotBlank는 URL 문자열의 null, 빈 문자열, 공백만 있는 값을 막습니다. @Min과 @Max는 재시도 횟수의 운영 범위를 제한합니다.
필수 숫자에는 원시 타입 int보다 Integer가 안전합니다. 값이 누락되면 int는 기본값 0이 되어 @Min(0) 검증을 통과할 수 있지만, Integer에 @NotNull을 적용하면 누락 자체를 구분할 수 있습니다.
ignoreUnknownFields = false를 사용하면 max-retires처럼 철자가 틀린 키도 시작 실패로 드러납니다.
설정 클래스 등록
애플리케이션 시작 클래스에 스캔을 활성화합니다.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
특정 클래스만 등록하려면 @EnableConfigurationProperties(PaymentProperties.class)를 사용할 수도 있습니다.
이제 다음처럼 잘못된 설정으로 실행해 봅니다.
payment:
base-url: " "
timeout: 3s
max-retries: 10
애플리케이션 컨텍스트를 만드는 과정에서 검증이 실패하므로 서버가 트래픽을 받기 전에 문제를 발견할 수 있습니다. 서비스에는 PaymentProperties를 생성자로 주입합니다. 문자열 키가 서비스 코드에 퍼지지 않아 IDE 자동 완성과 타입 검사를 활용할 수 있습니다.
운영에서는 PAYMENT_BASE_URL, PAYMENT_TIMEOUT, PAYMENT_MAX_RETRIES 같은 환경 변수로 덮어쓸 수 있습니다. API 키와 비밀번호는 YAML에 커밋하지 말고 Secret Manager나 배포 시스템의 비밀 변수로 주입합니다.
중첩 설정 검증
인증 정보를 중첩 객체로 분리한다면 @Valid를 붙여 내부 제약까지 연쇄 검증해야 합니다.
public record PaymentProperties(
@NotBlank String baseUrl,
@NotNull @Valid Auth auth
) {
public record Auth(
@NotBlank String clientId,
@NotBlank String clientSecret
) {
}
}
중첩 필드의 @Valid를 빠뜨리면 내부 제약이 실행되지 않을 수 있습니다.
자주 하는 실수
- 스캔 또는 클래스 등록을 하지 않습니다.
@Validated나 Validation 의존성을 빠뜨립니다.- 필수 숫자를 원시 타입으로 선언해 누락이 기본값으로 숨습니다.
- 중첩 객체에
@Valid를 붙이지 않습니다. - 운영 비밀값을
application-prod.yml에 직접 저장합니다. - 타임아웃에 단위 없는 숫자를 사용해 사람이 기대한 단위와 실제 단위가 달라집니다.
핵심 요약
- 관련 설정은
@ConfigurationProperties로 한 객체에 묶습니다. @Validated와 Jakarta Validation 제약으로 시작 시점에 값을 검사합니다.- 필수 숫자는 래퍼 타입과
@NotNull을 함께 사용합니다. ignoreUnknownFields = false로 설정 키 오타를 빠르게 발견할 수 있습니다.- 중첩 속성에는
@Valid, 운영 비밀에는 별도 비밀 저장소를 사용합니다.
잘못된 설정을 요청 처리 코드에서 발견하는 것은 너무 늦습니다. 설정도 애플리케이션 입력값이라는 관점에서 타입과 범위를 정의하면, “배포는 됐지만 첫 요청부터 실패하는” 장애를 시작 단계에서 차단할 수 있습니다.
함께 읽으면 좋은 글:
최종 확인: 2026-07-30
'Programming > Spring Boot' 카테고리의 다른 글
| Spring Boot Actuator readiness·liveness 설정: 배포 트래픽을 안전하게 제어하는 방법 (0) | 2026.08.04 |
|---|---|
| Spring Boot 테스트 슬라이스 선택법: @WebMvcTest·@DataJpaTest·@SpringBootTest 차이 (0) | 2026.08.03 |
| Spring Boot Graceful Shutdown 설정: 배포 중 요청을 안전하게 종료하는 방법 (0) | 2026.07.28 |
| Spring Boot LTS는 없을까? 4.1·4.0·3.5 지원 기간과 버전 선택 (0) | 2026.07.14 |
| Spring Boot JPA N+1 문제 해결하기 (0) | 2026.06.30 |