--- title: Spring Boot 3 @ConfigurationProperties record 에 보조 생성자를 추가하면 바인딩이 깨지는 이유 source_type: blog-topic status: raw created: 2026-06-12 related_branches: [feature-domain-event-outbox-contract] related_projects: [ca-tmpl] tags: [blog-topic, ca-tmpl, spring-boot, configuration-properties, record, constructor-binding, java21] status_label: ready-for-canonical target_audience: backend-engineer inspiration_url: archive_url: --- # Spring Boot 3 `@ConfigurationProperties` record 에 보조 생성자를 추가하면 바인딩이 깨지는 이유 ## Parent [[raw/branch-notes/feature-domain-event-outbox-contract]] --- ## 글감 씨앗 `OutboundHttpSettings` record 에 기존 호출부 호환을 위한 보조 6-arg 생성자를 추가했을 때, `ApplicationContextRunner` 로 바인딩을 테스트하자 `No default constructor found` 로 실패한 경험. 해결책은 `@ConstructorBinding` 을 canonical compact constructor 에 추가하는 것이었다. --- ## 블로그 글 아이디어 ### 제목 후보 - "Spring Boot 3 `@ConfigurationProperties` 레코드에 보조 생성자를 추가하면 생기는 일" - "왜 Java record 에 생성자를 하나 더 추가했더니 Spring Boot 설정 바인딩이 깨졌나" ### 핵심 메시지 Spring Boot 3.x 는 record 에 생성자가 **딱 하나**일 때만 자동으로 constructor binding 경로를 선택한다. 생성자가 둘 이상이면 일반 JavaBean 경로(no-arg constructor 탐색)로 fallback 하기 때문에, 보조 생성자를 추가하는 순간 기존에 잘 돌던 바인딩이 깨진다. ### 커버할 내용 1. Spring Boot `@ConfigurationProperties` 에서 record 바인딩이 동작하는 원리 (single-constructor auto-detect) 2. 보조 생성자 추가 시 발생하는 예외 메시지와 스택 트레이스 분석 3. 해결책: `@ConstructorBinding` (from `org.springframework.boot.context.properties.bind`) 을 canonical compact constructor 에 명시 4. Spring Boot 2.x vs 3.x import 경로 차이 (`@ConstructorBinding` deprecated 위치 변경) 5. 실전 패턴: 기존 호출부 호환을 유지하면서 record 필드를 확장하는 방법 (보조 생성자 + `@ConstructorBinding`) ### 코드 예시 ```java @ConfigurationProperties(prefix = "app.outbound.http") public record MySettings( Duration connectTimeout, Retry retry) { @ConstructorBinding // 다중 생성자 record 필수! public MySettings { /* validation */ } /** 보조 생성자: 기존 호출부 호환 */ public MySettings(Duration connectTimeout) { this(connectTimeout, null); } } ``` ### 독자 대상 Java 21 + Spring Boot 3.x 를 사용하며 `@ConfigurationProperties` 를 record 로 작성하는 개발자. --- ## Claims To Verify - Spring Boot 3.4 릴리즈 노트에 이 동작의 공식 문서 여부 확인 필요. - `@ConstructorBinding` import 경로 변경 이력 (2.x → 3.x) 공식 마이그레이션 가이드 인용 필요. ## 트리거 / Trigger - 트리거 유형: `troubleshooting` - 트리거 날짜: 2026-06-12 - 트리거 연결 노트: [[raw/branch-notes/feature-domain-event-outbox-contract]] ## 글감 / Topic seed - 한 문장 요지: Spring Boot 3 record `@ConfigurationProperties`에 보조 생성자를 추가하면 constructor binding auto-detect가 깨질 수 있어 canonical constructor에 `@ConstructorBinding`을 명시해야 한다. - 예상 제목 후보: - Spring Boot 3 record configuration binding이 깨지는 이유 - 보조 생성자와 `@ConstructorBinding`의 함정 ## 핵심 주장 후보 / Claim candidates - 사실 후보: - multi-constructor record는 single-constructor auto-detect 경로를 벗어날 수 있다. - 의견/해석 후보: - backward-compatible constructor를 추가할 때 binding entrypoint를 명시하는 테스트가 필요하다. ## Outline seed 1. record binding auto-detect와 multi-constructor fallback을 설명한다. 2. `ApplicationContextRunner` failure로 원인을 좁힌다. 3. `@ConstructorBinding` import 경로와 canonical constructor 명시 패턴을 정리한다. ## Canonical 전환 후보 / Canonical extraction candidates - `wiki/projects/ca-tmpl/config-and-adapter-templates.md` 후보: - configuration properties record binding troubleshooting 글감. - 필요한 추가 검증: - 공식 문서/마이그레이션 가이드 source 보강. ## Sources / 근거 후보 - [[raw/branch-notes/feature-domain-event-outbox-contract]] ## 미해결 / Unknown - 아직 확인해야 할 사실: Spring Boot 3.x 공식 문서의 정확한 constructor binding 문구. - 과장하면 안 되는 부분: 모든 record multi-constructor가 동일하게 실패한다고 단정하지 않는다. ## Decision / 처리 결정 - 액션: `promote-to-canonical` - 이유: `wiki/projects/ca-tmpl/config-and-adapter-templates.md` 에 Spring Boot 3 record configuration binding 글감으로 반영한다. - 다음 단계: blogify 전 official doc 근거를 보강한다. ## Related / 관련 - 관련 branch: [[raw/branch-notes/feature-domain-event-outbox-contract]]