# @ConfigurationProperties 사용 기준 ## 목적 외부 설정은 산발적인 문자열 주입이 아니라, **의미 있는 설정 객체**로 묶어 관리한다. 설정은 business object가 아니라 **configuration contract** 로 취급한다. ## 공식 의미 - `@ConfigurationProperties`는 externalized configuration을 타입 안전하게 바인딩하기 위한 애노테이션이다. - 클래스 또는 `@Configuration` 안의 `@Bean` 메서드에 붙일 수 있다. - 바인딩은 setter 또는 생성자 인자를 통해 수행될 수 있다. - `@EnableConfigurationProperties` 또는 `@ConfigurationPropertiesScan`으로 등록할 수 있다. - `@ConfigurationProperties`는 `@Value`보다 relaxed binding, metadata 지원에 유리하다. - `@ConfigurationProperties`는 SpEL을 평가하지 않는다. - `@ConfigurationPropertiesScan`은 `@Component`가 붙은 클래스를 스캔 대상으로 잡지 않는다. - `@Validated`로 properties validation을 수행할 수 있다. - `Optional`은 `@ConfigurationProperties`에서 권장되지 않는다. ## 기본 규칙 ### 1. 의미 있는 설정 그룹은 `@ConfigurationProperties` 우선 다음은 `@ConfigurationProperties`를 우선 검토한다. - 같은 prefix 아래 여러 설정값이 함께 움직임 - 계층형/nested 설정이 있음 - 설정 검증이 중요함 - 여러 bean이 같은 설정 집합을 참조함 - 운영 문서와 IDE metadata 지원이 중요함 예: - Vault 설정 - OAuth client 설정 - JWT 설정 - scheduler/retry 설정 - feature toggle 묶음 ### 2. 단발성 한두 값만 필요하면 `@Value`를 제한적으로 허용 다음은 `@Value`를 허용할 수 있다. - 단일 상수성 설정값 - 로컬 config class 안에서만 쓰는 매우 작은 값 - SpEL이 실제로 필요한 경우 단, 애플리케이션 자체 설정 키 집합이라면 `@ConfigurationProperties`를 우선한다. ### 3. properties class는 설정 계약만 표현 `@ConfigurationProperties` 클래스의 책임은: - 설정값 구조 표현 - 타입 안전 바인딩 - 검증 - 합리적 기본값 표현 다음은 넣지 않는다. - business logic - 외부 API 호출 - repository/service 호출 - 큰 계산 로직 - runtime mutable state ### 4. prefix는 명확하고 안정적으로 설계 prefix는 기능/도메인 경계를 드러내야 한다. 좋은 방향: - `auth.jwt` - `auth.oauth.google` - `vault.transit` - `app.retry` 지양: - `config` - `common` - `misc` - 의미가 너무 넓은 prefix ### 5. 등록 방식은 스캔과 명시 등록을 구분 기본 선택: - 애플리케이션 내부 일반 설정 타입 -> `@ConfigurationPropertiesScan` - 조건부 등록/auto-configuration/명시적 wiring 필요 -> `@EnableConfigurationProperties` 또는 `@Bean` + `@ConfigurationProperties` ### 6. `@Component`와 `@ConfigurationProperties`를 습관적으로 같이 쓰지 않는다 properties class는 설정 바인딩 타입이지 일반 component가 아니다. 기본: - scanning 대상 properties -> `@ConfigurationPropertiesScan` - 명시 등록이 필요하면 `@EnableConfigurationProperties` `@Component`를 붙여 일반 bean처럼 다루는 패턴은 지양한다. ### 7. 가능한 한 immutable 구조를 선호 설정은 보통 startup 후 바뀌지 않는 계약이다. 기본 방향: - 생성자 기반 바인딩 또는 immutable한 구조 선호 - 변경 가능한 setter-only bag object를 기본값으로 삼지 않음 - 필수 설정은 생성 시점에 확정되게 설계 ### 8. `Optional` 필드 금지 Spring Boot 공식 문서상 `Optional`은 `@ConfigurationProperties`에서 권장되지 않는다. 기본: - nullable field - 기본값 - nested object - 명시적 default object 중 하나로 표현한다. ### 9. validation은 startup에서 최대한 실패하게 설정이 잘못되면 런타임 깊은 지점에서 터지지 않게, 바인딩 시점 검증을 우선한다. 기본: - `@Validated` - Bean Validation annotation (`@NotNull`, `@Min`, `@Pattern` 등) - nested properties는 필요 시 `@Valid` ### 10. 기본값 정책을 숨기지 않는다 기본값은 다음 중 하나로 명시한다. - 필드 기본값 - 생성자 기본값 - 명시적 nested default object - 문서화된 운영 기본값 “값이 없으면 나중에 어딘가에서 처리”를 금지한다. ### 11. Environment 직접 조회보다 properties bean 주입 우선 application/service/infrastructure 코드에서 `Environment#getProperty(...)`를 흩뿌리지 않는다. 기본: - 관련 설정은 properties 객체로 묶고 - 필요한 bean에 주입한다 예외: - truly dynamic property lookup - framework/bootstrap 초기화 특수 상황 ### 12. 설정 객체는 소유 모듈 가까이에 둔다 properties class는 그것을 사용하는 기능/모듈 옆에 둔다. 예: - `vault` 설정은 vault adapter/config 근처 - `jwt` 설정은 jwt/token 모듈 근처 `CommonProperties`, `AppProperties`처럼 전역 잡동사니 설정 객체는 지양한다. ### 13. third-party bean 바인딩도 가능하지만, 범위를 제한 외부 라이브러리 객체를 `@Bean` 메서드 + `@ConfigurationProperties`로 바인딩할 수 있다. 단, 그 경우도: - 명확한 prefix - 명확한 config class - 외부 라이브러리 설정 범위 제한 을 지킨다. ### 14. 설정 계약과 business meaning을 혼동하지 않는다 예: - `token-expiration-seconds`는 설정 계약 - `TokenTtl`은 도메인 의미일 수 있다 필요하면 properties -> domain config/value object 변환 단계를 둔다. 설정 타입을 그대로 domain everywhere에 흘려보내지 않는다. ### 15. 문서와 metadata를 함께 고려 `@ConfigurationProperties`의 장점 중 하나는 metadata/IDE 지원이다. 애플리케이션이 제공하는 설정 키는: - prefix 일관성 - 이름 일관성 - 설명/문서화 를 함께 고려한다. ## 프로젝트 기준 요약 - 의미 있는 설정 집합은 `@ConfigurationProperties` 우선 - 한두 개 단발성 값만 `@Value` 제한 허용 - properties class는 설정 계약만 표현 - `@Component`와 습관적 결합 금지 - immutable 구조 선호 - `Optional` 필드 금지 - validation은 startup에서 최대한 실패하게 - `Environment` 직접 조회보다 properties bean 주입 우선 - 설정 객체는 owning module 가까이에 둔다