Spring AutoConfiguration의 동작 원리

Spring AutoConfiguration의 동작 원리

스프링 부트의 목표

스프링의 복잡한 설정을 최소화하고,
개발자가 빠르게 실행 가능한 애플리케이션을 만들 수 있도록 하는 프레임워크이다.

예를 들어, Redis에 연결된 스프링 애플리케이션을 만들고 싶을 때 우리는
spring-boot-starter-data-redis 의존성을 추가해주면 redisTemplate 빈과 연결 설정이 가능하다.

별도의 설정 없이 RedisTemplate 타입의 빈을 주입받아 사용할 수 있다.

이처럼 스프링 부트의 핵심은 자동 설정과 내장 서버(Tomcat ...)라고 볼 수 있다.

Spring Boot의 AutoConfiguration의 마법 같은 기능은 어떻게 동작하는 것일까?

애플리케이션 실행 과정

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

@SpringBootApplication 어노테이션의 구성

@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
  @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
}

큰 흐름은 @ComponentScan을 통해 개발자가 정의한 Component들이 Bean으로 먼저 등록이 되고,

@EnableAutoConfiguration을 통해 애플리케이션 구성에 필요한 추가 Bean을 읽어서 등록하게 된다.

@EnableAutoConfiguration

위 어노테이션이 스프링 부트의 자동 설정 기능을 활성화하는 역할을 수행한다.

@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Inherited  
@AutoConfigurationPackage  
@Import({AutoConfigurationImportSelector.class})  
public @interface EnableAutoConfiguration {  
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";  
  
    Class<?>[] exclude() default {};  
  
    String[] excludeName() default {};  
}

자세히 보면
@Import({AutoConfigurationImportSelector.class})
를 import하고 있는 것을 확인할 수 있다.

@SpringBootApplication
  - @EnableAutoConfiguration
    - @Import({AutoConfigurationImportSelector.class})  

해당 클래스에서는 자동 구성할 후보 빈들을 불러와 제외되거나 중복된 빈들을 제거하는 작업을 거친 후 자동 구성할 빈들을 반환하는 역할을 수행한다.

AutoConfiguraionImportSelector.class

selectImports()

해당 클래스 내부에는 selectImports 라는 메서드가 존재한다.

해당 메서드를 통해 Imprt할 클래스가 무엇인지 알 수 있게 된다.
해당 메서드는 getAutoConfigurationEntry(..)를 호출하여 엔트리를 반환받게 된다.

즉, 자동 설정의 진짜 시작점이라고 볼 수 있다.

getAutoConfigurationEntry()

자동 설정 후보 리스트를 다듬는 핵심 메서드.

후보 클래스 로딩getCandidateConfigurations 호출 (spring.factories / imports 읽음).

  1. 중복 제거.
  2. 제외할 클래스 확인 (exclude 속성 등).
  3. 조건 필터링@ConditionalOnClass, @ConditionalOnMissingBean 같은 조건 체크.
  4. 이벤트 발행 (fireAutoConfigurationImportEvents) → 확장 포인트 제공.
  5. 결과 묶기AutoConfigurationEntry 객체에 후보/제외 정보 담아서 반환.

즉, 후보들 중에서 실제 등록 가능한 자동 설정 클래스만 추리는 단계

getCandidateFigurations()

이는 자동 설정 원천 후보 클래스를 로딩하는 역할을 수행한다.
META -INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

에서 매핑된 클래스 이름들을 모두 읽어온다.

즉, 자동 설정의 풀(pool) 후보를 모아오는 단계.

정리

main()
└─ SpringApplication.run()
└─ refresh()
└─ registerAnnotationConfigProcessors()
└─ ConfigurationClassPostProcessor 등록
└─ invokeBeanFactoryPostProcessors()
└─ ConfigurationClassPostProcessor 실행
└─ @EnableAutoConfiguration 처리
└─ @Import(AutoConfigurationImportSelector)
└─ selectImports()
└─ getAutoConfigurationEntry()
└─ getCandidateConfigurations()
└─ 후보 정리(중복 제거, 제외, 조건 검사)
└─ 최종 클래스 반환
└─ BeanDefinition 등록

스프링 부트의 자동 설정은 @EnableAutoConfiguration 으로 시작해 AutoConfigurationImportSelector 가 후보 설정 클래스를 수집·필터링하고, ConfigurationClassPostProcessor 가 이를 BeanDefinition 으로 등록하는 구조다.

이 과정은 스프링 컨텍스트 초기화 시점에 ConfigurationClassPostProcessor가 자동으로 호출하면서 진행된다.

즉, 의존성만 추가하면 조건(@ConditionalOnClass, @ConditionalOnMissingBean 등)에 맞는 Bean이 자동 등록되어 개발자는 최소한의 설정만으로 실행 가능한 애플리케이션을 만들 수 있다.