Files
llm-wiki/vault/10-projects/errors/spring-configuration-bean-factory-method-not-processed-2026-06-11.md
T

68 lines
5.2 KiB
Markdown

---
title: error / spring-configuration-bean-factory-method-not-processed-2026-06-11
source_type: error-note
status: raw
related_branches: [feature-outbound-http-client-baseline]
related_projects: [ca-skeleton]
tags: [error, ca-skeleton, spring, configuration, testing, applicationcontextrunner]
created: 2026-06-11
status_label: resolved
---
# error: spring-configuration-bean-factory-method-not-processed-2026-06-11
> Layer: `raw/errors/` — 작업 중 마주친 단일 실패·트러블슈팅 기록. 원본은 raw에 영구 보관한다.
## Parent / 부모
- [[raw/branch-notes/feature-outbound-http-client-baseline]] — D3 활성화 가드(retry enabled + MeterRegistry 부재 → 기동 실패) 테스트 작성 중 발생.
## 증상 / Symptom
- 에러 메시지 (원문 그대로):
```text
OutboundHttpResilienceConfigTest > application_context_fails_to_start_when_retry_enabled_and_no_meter_registry_bean() FAILED
java.lang.AssertionError at OutboundHttpResilienceConfigTest.java:138
```
- 발생 컨텍스트: `ApplicationContextRunner` 테스트가 `assertThat(ctx).hasFailed()` 를 어서션 — retry enabled + MeterRegistry 부재이므로 `OutboundHttpResilienceConfig.outboundHttpResilience()` 가 `IllegalStateException` 으로 기동을 실패시켜야 하는데, 컨텍스트가 **정상 기동**해 버림.
- 발생 환경: local, Spring Boot 3.5.14 테스트 (`ApplicationContextRunner`).
- 재현 가능 여부: `always`.
## 재현 절차 / Reproduction
1. 테스트 inner `@Configuration` 클래스에 `@Bean OutboundHttpResilienceConfig resilienceConfig() { return new OutboundHttpResilienceConfig(); }` 처럼 **다른 @Configuration 클래스를 @Bean 팩토리 메서드의 반환값으로 등록**.
2. `ApplicationContextRunner.withUserConfiguration(테스트Config.class).run(...)`.
3. 기대: `OutboundHttpResilienceConfig` 안의 `@Bean outboundHttpResilience(...)` 정의가 처리되어 기동 시 IllegalStateException.
4. 실제: 그 `@Bean` 메서드가 아예 빈 정의로 등록되지 않음 → 가드 코드가 실행되지 않고 컨텍스트 정상 기동 → `hasFailed()` 어서션 실패.
## 조사 단계 / Investigation log
- 2026-06-11 — 컨텍스트가 실패하지 않는 이유 추적 → `ConfigurationClassPostProcessor` 는 빈 정의의 클래스가 configuration 후보일 때만 `@Bean` 메서드를 처리하는데, **팩토리 메서드 산출물로 등록된 빈**은 그 대상이 아님(인스턴스가 단순 빈으로만 등록) → `@Configuration` 클래스는 `withUserConfiguration(...)` 등으로 **직접 구성 클래스로 등록**해야 함.
- 2026-06-11 — 테스트 수정: `resilienceConfig()` @Bean 메서드 제거 + `.withUserConfiguration(RetryEnabledNoMeterConfig.class, OutboundHttpResilienceConfig.class)` 로 등록, 불필요한 `@EnableAutoConfiguration` 도 제거 → 컨텍스트가 기대대로 기동 실패, `getStartupFailure().getMessage()` 에 "MeterRegistry" 포함 확인, green.
## 근본 원인 / Root cause
- 직접 원인: `@Configuration` 클래스를 다른 구성 클래스의 `@Bean` 팩토리 반환값으로 등록하면 그 안의 `@Bean` 메서드들이 빈 정의로 처리되지 않음.
- 근본 원인: Spring 의 구성 클래스 처리(`ConfigurationClassPostProcessor`)는 "구성 클래스로 등록된 빈 정의"를 스캔 단위로 삼는다 — 팩토리 메서드 산출 인스턴스는 평범한 빈일 뿐 구성 클래스 향상(enhancement)·@Bean 스캔 대상이 아니다.
- 트리거 조건: 테스트에서 구성 클래스를 "new 해서 @Bean 으로 돌려주는" 식으로 우회 등록할 때.
## Sources / 근거
- 로컬 검증: `OutboundHttpResilienceConfigTest` — 수정 전 `hasFailed()` AssertionError / 수정 후 green (`./gradlew :adapter-outbound:test`). Spring 공식 문서의 해당 절 인용은 미보강 (`needs-confirmation` — @Configuration javadoc/reference 의 lite mode 절 추가 인용 권고).
## 해결 / Resolution
- 적용한 조치: 테스트의 구성 등록 방식을 `.withUserConfiguration(..., OutboundHttpResilienceConfig.class)` 직접 등록으로 교체, `@Bean` 팩토리 등록 제거.
- 검증 방법: `./gradlew :adapter-outbound:test` — 해당 테스트 포함 모듈 전체 green.
- 잔여 위험: 없음 (테스트 배선 문제 — 프로덕션 경로는 component-scan 으로 정상 등록).
## 회고 / Lessons
- 빨리 감지하는 신호: "컨텍스트가 실패해야 하는데 hasNotFailed/정상 기동" + 문제의 @Bean 정의가 컨텍스트에 아예 없음 → 구성 클래스 등록 경로(직접 등록 vs 팩토리 산출물)부터 확인.
- 예방 체크리스트: `ApplicationContextRunner` 에서 @Configuration 클래스는 항상 `withUserConfiguration(...)`/`withConfiguration(...)` 으로 직접 등록한다. @Bean 으로 돌려주지 않는다.
- wiki 일반화 후보: "Spring 구성 클래스는 '등록 방식'이 처리 여부를 결정한다 — 팩토리 산출 @Configuration@Bean 은 죽은 정의" (wiki/concepts 추출 후보).
## Related / 관련
- 관련 에러: [[raw/errors/micrometer-meterfilter-replacetagvalues-functioncounter-2026-06-11]], [[raw/errors/jdk-httpclient-dns-unresolvedaddress-connectexception-2026-06-11]] — 같은 branch 작업에서 발생.