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

5.2 KiB

title, source_type, status, related_branches, related_projects, tags, created, status_label
title source_type status related_branches related_projects tags created status_label
error / spring-configuration-bean-factory-method-not-processed-2026-06-11 error-note raw
feature-outbound-http-client-baseline
ca-skeleton
error
ca-skeleton
spring
configuration
testing
applicationcontextrunner
2026-06-11 resolved

error: spring-configuration-bean-factory-method-not-processed-2026-06-11

Layer: raw/errors/ — 작업 중 마주친 단일 실패·트러블슈팅 기록. 원본은 raw에 영구 보관한다.

Parent / 부모

증상 / Symptom

  • 에러 메시지 (원문 그대로):
    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 추출 후보).