Files
project-auth-server/docs/standards/spring/configuration-properties.md
T

6.2 KiB

@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 가까이에 둔다