본문 바로가기
WEB/SpringBoot

SpringBoot의 @EnableAutoConfiguration 동작 원리

by 정권이 내 2026. 3. 2.

🚀 SpringBoot 프레임워크 이해

새로운 프로젝트를 시작할때마다 Spring Boot의 편리함에 감탄하게 됩니다.

build.gradle 에 spring-boot-starter-web, spring-boot-starter-data-jpa 같은 의존성 몇 줄만 추가하고 애플리케이션을 실행하면, 내장 톰캣(Tomcat)이 뜨고, 데이터베이스 커넥션이 연결되며, REST API를 받을 준비가 끝납니다.

이 편리함에만 익숙해지고 실행 원리를 모른다면 특정 라이브러리가 내 의도와 다르게 설정되거나, 사내 공통 모듈을 만들 때 스프링 부트가 어떤 순서로 빈(Bean)을 로드하는지 모를때 실행 오류로 이어질 수 있습니다.

그래서 오늘은 Spring Boot Auto Configuration(자동 구성)의 핵심 원리와, main 메서드를 실행했을 때 애플리케이션이 구동되기까지의 전체 동작 과정을 확인 해보겠습니다.

😅 SpringBoot 자동 구성의 함정

SpringBoot 자동 구성 원리를 깊게 파보기 전에, 이 원리를 몰라서 마주치게 되는 시행착오들을 먼저 살펴보겠습니다.

1. "Failed to configure a DataSource" 에러의 늪

가장 흔하게 만나는 에러입니다. JPA나 MyBatis 같은 데이터베이스 관련 의존성을 추가해 놓고, application.yml에 DB 접속 정보(URL, Driver 등)를 적지 않고 무심코 앱을 실행했을 때 발생합니다.

이게 왜 발생할까요? 스프링 부트의 자동 구성이 클래스패스에 HikariCP 나 DataSource 관련 클래스가 있는 것을 감지하고, DB 연결 빈을 생성하려 시도하기 때문입니다. 하지만 정작 필요한 접속 정보가 없으니 예외를 던지며 애플리케이션을 종료시킵니다.

2. 내가 만든 커스텀 빈(Bean)이 무시당하는 현상

사내 공통 라이브러리나 특정 모듈을 개발할 때, 개발자가 직접 @Configuration 을 통해 등록한 빈과 스프링 부트가 자동으로 등록해 주는 빈의 이름/타입이 충돌하는 경우가 있습니다.

스프링 부트의 자동 구성은 대부분 @ConditionalOnMissingBean 이라는 조건부 애노테이션을 사용합니다.

즉, "개발자가 명시적으로 등록한 빈이 없을 때만 등록" 라는 뜻입니다. 그런데 컴포넌트 스캔 순서나 설정 파일의 구조를 잘못 잡으면, 개발자가 의도한 커스텀 빈이 등록되기도 전에 자동 구성 빈이 덮어써 버리거나 충돌 예외 BeanDefinitionOverrideException 가 발생하기도 합니다.

3. @ComponentScan의 위치 실수

간혹 Application.java (메인 클래스)를 프로젝트 최상위 패키지가 아닌, 하위 패키지(com.example.project.domain 등)에 만들어버리는 경우가 있습니다.

스프링 부트는 기본적으로 메인 클래스가 위치한 패키지와 그 하위 패키지들만 스캔합니다. 따라서 스프링 부트 애플리케이션의 메인 클래스는 반드시 프로젝트의 최상위 패키지(Root Package)에 위치시켜야 컴포넌트 스캔 누락을 방지할 수 있습니다.

🧠 Spring Boot 구동 과정과 자동 구성의 3대 핵심

스프링 부트 프로젝트의 메인 클래스에는 @SpringBootApplication 애노테이션이 붙어있습니다.

이 애노테이션 안에는 빈을 찾는 @ComponentScan 과 핵심인 @EnableAutoConfiguration이 있습니다.

우리가 SpringApplication.run() 을 호출해 애플리케이션을 실행하면, 내부적으로는 크게 다음 3가지 핵심 단계를 실행합니다.

1️⃣ 환경 준비(Environment)와 ApplicationContext 생성

애플리케이션이 구동되면 가장 먼저 application.yml 파일의 설정값과 OS 환경변수 등을 싹 다 읽어들여 통합된 Environment 객체를 구축합니다.

이후 스프링의 핵심인 IoC 컨테이너를 생성하고, 메인 클래스를 최초의 빈(Bean)으로 등록해 컴포넌트 스캔의 출발점을 잡습니다.

2️⃣ @EnableAutoConfiguration 의 조건부 빈(Bean) 등록

구동 과정의 가장 핵심 단계입니다. 메인 클래스에 있던 @EnableAutoConfiguration 이 작동하며, 텅 비어있던 IoC 컨테이너를 필요한 객체들로 꽉 채워줍니다. 이 과정은 다음 순서로 스마트하게 동작합니다.

  • 설정 목록 로드: 먼저 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일에 적힌 수백 개의 자동 구성 클래스 후보들을 읽어옵니다.
  • 클래스패스(Classpath) 확인: build.gradle 에 추가한 의존성들을 훑어보고 현재 프로젝트에 어떤 라이브러리들이 존재하는지 파악합니다.
  • application.yml 검사: 앞서 만든 Environment 객체를 뒤져서 개발자가 명시한 DB 접속 URL, 계정 정보 등의 설정값이 있는지 확인합니다.

💡 다양한 @Conditional 애노테이션의 역할

스프링 부트는 후보 목록에 있는 모든 설정을 다 적용하지 않습니다.

클래스패스와 application.yaml 을 바탕으로 조건을 평가하여 부합할 때만 빈으로 등록합니다.

  • @ConditionalOnClass: 특정 클래스가 클래스패스에 존재할 때만 동작합니다. (예: Tomcat.class 가 존재하면 내장 톰캣 설정 활성화)
  • @ConditionalOnMissingBean: 특정 빈이 스프링 컨테이너에 없을 때만 동작합니다. (예: 개발자가 직접 DataSource 빈을 등록하지 않았을 때만 기본 DB 커넥션 세팅)
  • @ConditionalOnProperty: application.yml 에 특정 속성이 있을 때만 동작합니다. (예: spring.h2.console.enabled=true 속성이 있어야만 H2 콘솔 빈 등록)

결과적으로 이 조건들을 통과한 DataSource, EntityManager... 같은 자동 구성 Bean들과, 개발자가 @ComponentScan 영역에 작성한 커스텀 Bean인 @Service, @Controller 들이 모두 IoC 컨테이너에 등록됩니다.

💻 [코드 예시: 나만의 커스텀 자동 구성 만들기]

실무에서는 사내 공통 알림 모듈 같은 것을 만들 때 이 원리를 그대로 응용할 수 있습니다.

@AutoConfiguration
@ConditionalOnClass(SlackWebHookClient.class) // Slack 관련 라이브러리가 있을 때만 동작
@ConditionalOnProperty(prefix = "notification.slack", name = "webhook-url") // yml에 웹훅 URL이 있어야 동작
public class SlackNotificationAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean // 개발자가 직접 NotificationService를 만들지 않았을 때만 기본 제공
    public NotificationService slackNotificationService(
            @Value("${notification.slack.webhook-url}") String webhookUrl) {
        return new DefaultSlackNotificationService(webhookUrl);
    }
}

이렇게 만들어두면, 다른 팀원들은 그저 의존성을 추가하고 yml에 webhook-url 만 적어주면 알아서 NotificationService 빈이 생성되어 주입됩니다.

3️⃣ 내장 웹 서버(Embedded Web Server) 기동

앞선 2단계의 자동 구성 과정에서 클래스패스에 spring-boot-starter-web이 존재했다면, 톰캣 내장 웹 서버 Bean이 이미 컨테이너에 세팅되었을 것입니다.

이제 마지막으로 웹 서버를 초기화하고, application.yml 에 지정된 포트를 열어 외부 HTTP API 요청을 받을 준비를 최종 완료합니다.

🎯 마무리: 3줄 요약

오늘 배운 핵심 내용을 3줄로 깔끔하게 요약해 보겠습니다.

  1. 스프링 부트의 Auto Configuration은 @EnableAutoConfiguration을 통해 활성화되며, 미리 정의된 설정 목록을 로드한다.
  2. 무조건 등록되는 것이 아니라, 현재 클래스패스와 프로퍼티 환경을 분석해 @Conditional 조건에 부합하는 빈(Bean)만 스마트하게 등록한다.
  3. SpringApplication.run()은 Environment 세팅 ➡️ Context(컨테이너) 생성 ➡️ 자동 구성 및 컴포넌트 스캔(refresh) ➡️ 내장 웹 서버 구동의 순서로 동작한다.
반응형

댓글