Spring Boot 자동 구성은 어떤 조건을 먼저 평가하는가

seonwoo_jung·2026년 6월 20일

1. 도입

Spring Boot를 쓰다 보면 "왜 이 Bean은 생겼고, 저 Bean은 왜 빠졌지?"라는 질문을 자주 만난다. 의존성을 하나 추가했을 뿐인데 DataSource나 WebMvc 설정이 생기고, 내가 직접 Bean을 등록하면 Boot의 기본 Bean이 조용히 물러난다. 겉으로는 마법처럼 보이지만 실제로는 자동 구성 클래스와 @Conditional 평가가 차례로 맞물린 결과다.

이번 글에서는 Spring Boot Reference의 자동 구성 문서를 기준으로, 자동 구성에서 조건이 어떤 층위로 평가되는지와 Condition Evaluation Report를 어떻게 읽어야 하는지 정리했다. 핵심은 "조건 하나하나의 순서"보다 어떤 후보가 먼저 들어오고, 어떤 단계에서 조건이 걸러지는지를 보는 것이다.

자동 구성 디버깅은 Bean 목록을 보는 것보다 조건의 탈락 이유를 먼저 보는 편이 빠르다.

2. 자동 구성 후보는 어떻게 들어오는가

Spring Boot의 자동 구성은 애플리케이션 코드 전체를 무작정 스캔해서 결정되지 않는다. Spring Boot Reference에 따르면 자동 구성 클래스는 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일에 등록된 후보 목록을 통해 가져온다. 이 후보들은 @SpringBootApplication 안에 포함된 @EnableAutoConfiguration 흐름에서 애플리케이션 컨텍스트로 import될 수 있는 대상으로 다뤄진다.

후보가 들어왔다고 해서 곧바로 모든 Bean이 등록되는 것은 아니다. 자동 구성 클래스나 그 안의 @Bean 메서드에는 @ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty 같은 조건이 붙어 있다. 조건이 맞으면 해당 구성이나 Bean 정의가 살아남고, 맞지 않으면 등록 대상에서 제외된다.

흐름을 단순화하면 다음과 같다.

AutoConfiguration.imports
        |
        v
자동 구성 후보 목록
        |
        v
정렬 및 필터링
        |
        v
@Conditional 평가
        |
        +-- match    -> Bean definition 등록 가능
        +-- no match -> Condition Evaluation Report에 이유 기록

여기서 주의할 점은 자동 구성의 순서 지정과 Bean 생성 순서를 섞어 생각하면 헷갈린다는 것이다. Spring Boot 문서에서는 자동 구성 클래스 사이의 순서를 before, after, @AutoConfigureOrder 등으로 조정할 수 있다고 설명한다. 다만 이 순서는 자동 구성 클래스가 적용되는 순서에 관한 것이며, 실제 Bean 인스턴스 생성 순서는 의존 관계와 컨테이너의 Bean 생성 규칙에 의해 다시 결정된다.

3. 조건 평가는 한 줄로 끝나지 않는다

@Conditional은 Spring Framework의 조건부 등록 메커니즘 위에 있다. Spring Boot는 여기에 자주 쓰는 조건 애노테이션을 얹어 자동 구성에 맞게 제공한다. 예를 들어 다음과 같은 조건들이 대표적이다.

조건주로 확인하는 것예시 상황
@ConditionalOnClass클래스패스에 특정 클래스가 있는가JDBC 드라이버나 Servlet API 존재 여부
@ConditionalOnMissingClass클래스패스에 특정 클래스가 없는가충돌 가능성이 있는 구현 제외
@ConditionalOnBean이미 등록된 Bean이 있는가다른 설정을 기반으로 보조 Bean 등록
@ConditionalOnMissingBean사용자가 직접 등록한 Bean이 없는가Boot 기본값을 백오프로 제공
@ConditionalOnProperty설정 프로퍼티가 특정 값인가기능 on/off 플래그
@ConditionalOnWebApplication웹 애플리케이션인가MVC, WebFlux 관련 자동 구성

평가 순서를 이해할 때는 조건 애노테이션의 나열 순서를 외우기보다, 조건이 의존하는 정보가 언제 준비되는지를 보는 편이 낫다. 클래스패스 조건은 비교적 이른 시점에 판단할 수 있다. 반면 @ConditionalOnBean이나 @ConditionalOnMissingBean은 이미 등록된 Bean definition 상태를 봐야 하므로, 자동 구성 적용 순서의 영향을 더 민감하게 받는다.

Spring Boot Reference도 @ConditionalOnMissingBean을 사용자가 기본 설정을 덮어쓸 수 있게 해 주는 흔한 예로 설명한다. 이 조건은 "사용자 Bean이 없을 때만 Boot가 기본 Bean을 제공한다"는 의미에 가깝다. 그래서 자동 구성에서 흔히 보는 패턴은 다음과 같다.

@AutoConfiguration
@ConditionalOnClass(MyClient.class)
public class MyClientAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    MyClient myClient(MyClientProperties properties) {
        // 사용자가 MyClient Bean을 직접 등록하지 않았을 때만 기본 Bean 제공
        return new MyClient(properties.endpoint());
    }
}

이 예시에서 MyClient 클래스가 클래스패스에 없으면 자동 구성 클래스 자체가 빠질 수 있다. 클래스가 있고 사용자가 MyClient Bean을 직접 등록하지 않았다면 기본 Bean이 등록된다. 만약 사용자가 같은 타입의 Bean을 등록했다면 @ConditionalOnMissingBean이 match되지 않아 Boot의 기본 Bean은 물러난다.

4. "먼저 평가된다"는 말의 두 가지 의미

자동 구성 조건의 평가 순서를 말할 때는 보통 두 가지가 섞인다.

첫째는 자동 구성 클래스 사이의 적용 순서다. 어떤 자동 구성이 다른 자동 구성보다 먼저 처리되어야 할 수 있다. 예를 들어 A 자동 구성이 만든 Bean definition을 B 자동 구성의 @ConditionalOnBean이 확인해야 한다면, 두 자동 구성의 상대 순서가 의미를 가진다. Spring Boot는 이런 경우를 위해 자동 구성 간 before/after 관계를 표현할 수 있게 한다.

둘째는 조건이 판단되는 시점이다. @ConditionalOnClass처럼 메타데이터와 클래스패스만으로 판단 가능한 조건은 구성 클래스를 파싱하는 단계에서 탈락시킬 수 있다. 반대로 Bean 존재 여부를 확인하는 조건은 등록 단계의 상태에 기대기 때문에, 같은 조건이라도 어디에 붙어 있는지에 따라 결과를 읽어야 한다.

그래서 "Spring Boot가 @ConditionalOnClass를 항상 모든 조건보다 먼저 평가한다"처럼 단정하면 위험하다. 사용자가 실제로 봐야 하는 것은 다음 질문이다.

  • 이 조건은 자동 구성 클래스에 붙어 있는가, @Bean 메서드에 붙어 있는가?
  • 이 조건은 클래스패스, 프로퍼티, 웹 애플리케이션 타입, Bean definition 중 무엇을 보는가?
  • 이 자동 구성은 다른 자동 구성보다 먼저 또는 나중에 적용되도록 지정되어 있는가?

특히 Bean 조건은 순서에 예민하다. @ConditionalOnMissingBean은 "컨테이너 전체 생명주기에서 영원히 이 Bean이 없을 것"을 증명하는 조건이 아니라, 조건 평가 시점에 검색 전략에 따라 해당 Bean을 찾지 못했다는 뜻에 가깝다. 그래서 자동 구성 작성자는 문서에서 권장하듯 사용자 정의 Bean이 먼저 고려될 수 있는 구조로 조건을 배치해야 한다.

5. Condition Evaluation Report 읽는 법

Condition Evaluation Report는 조건 평가 결과를 사람이 읽을 수 있게 모아 놓은 보고서다. Spring Boot Actuator 문서의 conditions endpoint는 configuration과 auto-configuration class의 condition 평가 정보를 제공한다고 설명한다. 또한 애플리케이션 실행 시 debug=true 또는 --debug를 사용하면 콘솔에서 조건 평가 보고서를 확인할 수 있다.

보고서는 보통 다음 관점으로 읽는다.

구역의미확인할 것
Positive matches조건이 맞아 적용된 자동 구성어떤 조건 때문에 살아남았는지
Negative matches조건이 맞지 않아 제외된 자동 구성빠진 이유가 클래스, Bean, 프로퍼티 중 무엇인지
Unconditional classes조건 없이 적용되는 자동 구성정말 조건이 없는 기본 구성인지

예를 들어 어떤 자동 구성이 빠졌다면 먼저 Negative matches에서 해당 클래스를 찾는다. 거기에 @ConditionalOnClass did not find required class처럼 나오면 의존성 문제일 가능성이 크다. @ConditionalOnProperty가 match되지 않았다면 설정값 이름, 기본값, prefix를 확인해야 한다. @ConditionalOnMissingBean이 match되지 않았다면 이미 등록된 Bean이 있는지, 테스트 구성이나 수동 @Bean이 끼어들었는지 보는 식이다.

실무에서 유용했던 순서는 이렇다.

  1. 기대한 자동 구성 클래스 이름을 Report에서 찾는다.
  2. Positive인지 Negative인지 확인한다.
  3. Negative라면 조건 메시지에서 탈락 원인을 하나로 좁힌다.
  4. 클래스패스 문제면 의존성, 프로퍼티 문제면 설정, Bean 문제면 사용자 정의 Bean과 자동 구성 순서를 확인한다.

이렇게 보면 "왜 Boot가 이 Bean을 안 만들었지?"라는 질문이 "이 조건이 어떤 입력을 보고 no match가 됐지?"로 바뀐다. 디버깅 범위가 꽤 줄어든다.

6. 정리

Spring Boot 자동 구성의 조건 평가는 단순히 애노테이션을 위에서 아래로 읽는 방식이 아니다. 자동 구성 후보가 먼저 정해지고, 자동 구성 간 순서가 반영되며, 각 조건은 자신이 필요로 하는 정보가 준비된 단계에서 match 또는 no match로 기록된다.

Condition Evaluation Report는 이 과정을 해석하는 가장 직접적인 힌트다. Bean 목록만 보면 결과만 보이지만, Report를 보면 왜 그 결과가 나왔는지가 보인다. 특히 @ConditionalOnClass, @ConditionalOnProperty, @ConditionalOnMissingBean의 메시지를 구분해서 읽으면 자동 구성 문제의 원인을 의존성, 설정, 사용자 Bean 충돌 중 하나로 빠르게 좁힐 수 있다.

다음에 더 파고들 만한 주제는 AutoConfiguration.imports 로딩 과정과 @ConditionalOnMissingBean의 search strategy다. 이 둘을 이해하면 "내 Bean이 있는데 왜 Boot 기본 Bean도 생겼지?" 같은 문제를 더 정확히 추적할 수 있다.

참고 자료

  • Spring Boot Reference, Creating Your Own Auto-configuration
  • Spring Boot Actuator API, Conditions Evaluation Report (conditions)

0개의 댓글