classpath에 JAR 하나 넣었을 뿐인데 DataSource가 만들어진 이유 — 자동 구성의 작동 원리

Spring Boot 프로젝트에 spring-boot-starter-data-jpa 의존성을 추가했다. 코드 한 줄 안 고쳤는데 — DataSource, JdbcTemplate, EntityManagerFactory, TransactionManager bean이 자동으로 생성된다. 어떻게? Spring Boot가 자동 구성(auto-configuration)이라는 메커니즘으로, classpath에 있는 클래스와 정의된 프로퍼티를 기반으로 bean을 추론하여 등록하기 때문이다.

이 글은 자동 구성의 작동 원리, @Conditional 계열 어노테이션, AutoConfiguration.imports 파일, 그리고 Spring Boot 4.0의 모듈화된 자동 구성 구조를 풀어간다. (Spring Boot Reference - Auto-configuration)

자동 구성이란 — "추론하는 bean 등록"

Spring Boot는 classpath, 정의된 bean, 프로퍼티를 검사하여 어떤 bean이 필요한지 추론한다. (Spring Boot Reference - Auto-configuration)

flowchart TD
    START["애플리케이션 시작"] --> SCAN["classpath 스캔<br/>(어떤 라이브러리가 있는가?)"]
    SCAN --> EVAL["@Conditional 평가<br/>(조건 만족?)"]
    EVAL --> MATCH{조건 만족?}
    MATCH -->|Yes| REGISTER["bean 등록"]
    MATCH -->|No| SKIP["건너뜀"]
    REGISTER --> DONE["애플리케이션 준비 완료"]
    SKIP --> DONE

예를 들어, H2Database 클래스가 classpath에 있고 사용자가 DataSource를 직접 정의하지 않았다면 — Spring Boot가 H2 인메모리 DataSource bean을 자동 등록한다.

비유: 자동 구성은 냉장고를 보고 저녁 메뉴를 추천해 주는 요리 어시스턴트와 같다. 냉장고(classpath)에 돼지고기와 김치가 있으면 → 김치찌개를 만들어 준다. 하지만 사용자가 "오늘은 피자 먹을래"라고 직접 정의하면 → 어시스턴트는 물러난다. 자동 구성은 "사용자가 정의하지 않은 것"만 채운다.

내부적으로 이 추론은 어떻게 일어나는가? Spring Boot가 시작되면:

  1. 자동 구성 클래스 발견: 모든 JAR의 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일을 읽는다. Spring Boot 4.0의 모듈화 구조에서는 각 기능 모듈(data-jpa, web, security)이 자신의 imports 파일을 가진다.
  2. 조건 평가: 각 자동 구성 클래스의 @Conditional 어노테이션을 평가한다. @ConditionalOnClass(DataSource.class)ClassLoaderDataSource 클래스가 있는지 확인한다 — 있으면 통과, 없으면 그 자동 구성 클래스 전체를 건너뛴다.
  3. bean 등록 또는 건너뜀: 조건이 통과하면 @Bean 메서드를 실행하여 bean을 등록한다. 통과하지 못하면 아무 일도 일어나지 않는다.

이 3단계가 수백 개의 자동 구성 클래스에 대해 실행된다 — 시작 시간의 대부분이 이 평가에 쓰인다. --debug 플래그로 어떤 클래스가 통과/실패했는지 볼 수 있다 (아래 "자동 구성 확인" 절 참조).

// Spring Boot 4 / Java 25 — 사용자가 작성하지 않아도 되는 것
// @Bean DataSource dataSource() { ... }  ← 자동 구성이 해줌
// @Bean JdbcTemplate jdbcTemplate() { ... }  ← 자동 구성이 해줌
// @Bean PlatformTransactionManager txManager() { ... }  ← 자동 구성이 해줌

// 사용자는 비즈니스 로직만 작성
@Service
public class UserService {
    private final UserRepository repo;
    public UserService(UserRepository repo) { this.repo = repo; }
    // ...
}

@Conditional — 자동 구성의 엔진

자동 구성은 Spring Framework의 @Conditional 메커니즘 위에 구축된다 (02-spring-framework 장 04 참조). Spring Boot가 제공하는 주요 조건 어노테이션:

어노테이션 조건
@ConditionalOnClass(name="...") classpath에 특정 클래스가 존재
@ConditionalOnMissingBean 특정 타입의 bean이 아직 등록되지 않음
@ConditionalOnProperty(name="...", havingValue="...") 프로퍼티 값이 조건과 일치
@ConditionalOnWebApplication 웹 애플리케이션 환경
@ConditionalOnBean(type="...") 특정 bean이 이미 등록됨
@ConditionalOnResource(resources="...") classpath에 특정 리소스 존재
// Spring Boot 4 / Java 25 — 자동 구성 클래스 예 (개념)
import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.context.annotation.*;

@AutoConfiguration   // Spring Boot 자동 구성 클래스
@ConditionalOnClass(DataSource.class)           // DataSource가 classpath에 있으면
@ConditionalOnMissingBean(DataSource.class)      // 사용자가 정의하지 않았으면
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(DataSourceProperties props) {
        return props.initializeDataSourceBuilder().build();
    }
}

@ConditionalOnMissingBean이 자동 구성의 핵심이다 — 사용자가 직접 정의한 bean이 있으면 자동 구성이 물러난다. 이것이 "convention over configuration"을 가능하게 하는 메커니즘이다. 사용자 정의가 항상 우선한다.

내부 메커니즘: @ConditionalOnMissingBean은 어떻게 "사용자가 정의했는지"를 알까? Spring은 bean 등록을 두 단계로 수행한다. 1단계: 사용자가 @Configuration 클래스에 정의한 @Bean@Component를 먼저 스캔하여 bean 정의(definition)를 등록한다. 2단계: 자동 구성 클래스의 차례가 오면, @ConditionalOnMissingBean이 BeanFactory에 "이미 이 타입의 bean이 등록되어 있는가?"를 물어본다. 있으면 → 자동 구성의 @Bean 메서드를 건너뛴다. 없으면 → 실행하여 bean을 등록한다.

비유: 회사에 "기본 노트북을 지급"하는 규정이 있다. 신입사원이 자기 노트북을 가져왔으면 — 지급을 건너뛴다. 가져오지 않았으면 — 회사 노트북을 준다. @ConditionalOnMissingBean은 "이미 가지고 있으면 안 준다"는 조건이다. 이 조건 덕분에 사용자가 커스텀 bean을 정의하면 자동 구성이 자동으로 비활성화된다.

AutoConfiguration.imports — 자동 구성 클래스 등록

Spring Boot 2.7+부터 자동 구성 클래스는 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일에 나열된다 (이전 spring.factories 방식 대체).

# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.autoconfigure.MyAutoConfiguration
com.example.autoconfigure.AnotherAutoConfiguration

Spring Boot 4.0은 모듈화된 구조를 가진다 — 각 기능(data-jpa, web, security 등)이 별도 모듈로 분리되어, 자동 구성 클래스도 모듈별로 관리된다. (Spring Boot 4.0 Blog) 더 작은 JAR, 더 빠른 시작, GraalVM AOT 친화적 구조.

자동 구성 확인 — "무엇이 등록됐는가?"

# Spring Boot 4 — 자동 구성 보고서 활성화
java -jar myapp.jar --debug
============================
CONDITIONS EVALUATION REPORT
============================

Positive matches:
   DataSourceAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'javax.sql.DataSource'
      - @ConditionalOnMissingBean (types: javax.sql.DataSource; ...) did not find any beans

Negative matches:
   JpaRepositoriesAutoConfiguration:
      - @ConditionalOnClass did not find required class 'jakarta.persistence.EntityManager'

--debug 플래그로 어떤 자동 구성이 적용됐고, 어떤 것이 건너뛰어졌는지 확인할 수 있다. 문제 발생 시 가장 먼저 확인해야 할 도구다.

자동 구성 비활성화 / 제외

// Spring Boot 4 / Java 25 — 특정 자동 구성 제외
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApp { ... }
# application.yml
spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

@SpringBootApplication — 3개의 어노테이션 합체

// Spring Boot 4 / Java 25 — @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan
@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}
구성 요소 역할
@SpringBootConfiguration @Configuration과 동일 — bean 정의의 진입점
@EnableAutoConfiguration 자동 구성 활성화
@ComponentScan @Component 계열 자동 검색

@ConfigurationProperties — 타입 안전 프로퍼티 바인딩

// Spring Boot 4 / Java 25 — 프로퍼티를 객체로 바인딩
@ConfigurationProperties(prefix = "app.payment")
public record PaymentProperties(
    String apiKey,
    int timeout,
    boolean sandbox
) {}

// application.yml
# app:
#   payment:
#     api-key: sk_test_12345
#     timeout: 5000
#     sandbox: true

@Service
public class PaymentService {
    private final PaymentProperties props;

    public PaymentService(PaymentProperties props) { this.props = props; }
    // props.apiKey() → "sk_test_12345"
}

@ConfigurationProperties@Value보다 타입 안전하다 — 프로퍼티가 record 필드에 매핑되어 컴파일 타임 검증이 가능하고, IDE 자동 완성이 지원된다. Spring Boot에서는 @Value보다 @ConfigurationProperties를 우선한다.

Spring Boot 4.0의 새로운 점

항목 Spring Boot 3 Spring Boot 4
Spring Framework 6.x 7.0
모듈 구조 단일 jar 모듈화된 jar (작고 집중된)
로깅 일반 텍스트 구조화된 로깅 (ECS, GELF)
JSP 지원 제거 (JSP 컨테이너 의존성 제거)
Java 최소 Java 17 Java 17 유지 (Java 25 권장)
테스트 JUnit 5 JUnit 6
GraalVM 23 GraalVM 25 (새 reachability metadata)

Spring Boot 4.0의 모듈화는 가장 큰 변화다 — 각 기능(web, data-jpa, security 등)이 별도 모듈로 분리되어, 필요한 것만 가져올 수 있다. 더 작은 이미지, 더 빠른 시작, 더 적은 메모리. (Spring Boot 4.0 Release)

실습 — 자동 구성 추론 체감

// Spring Boot 4 / Java 25 — AutoConfigDemo.java
// Spring 없이 조건부 bean 등록 패턴 시뮬레이션
import java.util.*;

public class AutoConfigDemo {
    public static void main(String[] args) {
        // classpath 환경 시뮬레이션
        Set<String> classpath = Set.of("DataSource", "EntityManager", "Tomcat");

        // 자동 구성 규칙 평가
        if (classpath.contains("DataSource") && !userDefinedDataSource()) {
            System.out.println("[자동 구성] DataSource bean 등록");
        }
        if (classpath.contains("EntityManager") && classpath.contains("DataSource")) {
            System.out.println("[자동 구성] JPA bean 등록");
        }
        if (classpath.contains("Tomcat")) {
            System.out.println("[자동 구성] 임베디드 Tomcat 시작");
        }
    }

    static boolean userDefinedDataSource() { return false; }   // 사용자 정의 없음
}
java AutoConfigDemo.java
[자동 구성] DataSource bean 등록
[자동 구성] JPA bean 등록
[자동 구성] 임베디드 Tomcat 시작

확인할 것: classpath에 있는 라이브러리를 기반으로 필요한 bean이 자동 등록된다. 사용자가 직접 정의하면 자동 구성이 물러난다.

자동 구성 실행 순서 — @AutoConfigureOrder, before, after

자동 구성 클래스 간의 실행 순서를 제어할 수 있다:

@AutoConfiguration(after = DataSourceAutoConfiguration.class)
// DataSource 자동 구성 이후에 실행
public class MyDbConfig { }

@AutoConfiguration(before = SecurityAutoConfiguration.class)
// Security 자동 구성 이전에 실행
public class MySecurityConfig { }

자동 구성 순서는 의존성 있는 bean이 먼저 등록되어야 할 때 중요하다. @AutoConfiguration(after = ...)으로 선행 조건을 명시한다. 순서를 지정하지 않으면 Spring이 bean 의존성 그래프로 순서를 추론한다.

요약 — 이 글의 결론

  • 자동 구성은 classpath + 프로퍼티 + 기존 bean을 기반으로 bean을 추론 등록한다. @ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty가 핵심 조건 어노테이션이다.
  • @ConditionalOnMissingBean이 "convention over configuration"의 핵심이다. 사용자 정의 bean이 있으면 자동 구성이 건너뛴다 — 사용자 정의가 항상 우선한다.
  • --debug 플래그로 자동 구성 보고서를 확인한다. 어떤 구성이 적용됐고 건너뛰어졌는지 파악하여 문제를 진단한다.
  • @ConfigurationProperties로 타입 안전 프로퍼티 바인딩을 한다. @Value보다 컴파일 타임 안전, IDE 지원, record와 결합.
  • Spring Boot 4.0은 모듈화된 구조다. 각 기능이 별도 모듈로 분리되어 더 작은 이미지, 더 빠른 시작, GraalVM AOT 친화적.

생각해 볼 문제

  1. @ConditionalOnMissingBean@Bean 순서에 의존하면 어떤 문제가 발생하는가? Spring Boot 4에서 어떻게 해결하는가?
  2. @AutoConfiguration@Configuration의 차이는 무엇인가? 자동 구성 클래스는 왜 별도 어노테이션이 필요한가?
  3. GraalVM native image 환경에서 자동 구성의 조건 평가가 어떻게 달라지는가? (AOT 처리)
  4. Spring Boot 4에서 spring.factories 파일이 완전히 제거됐다면, 레거시 라이브러리는 어떻게 호환되는가?
  5. @ConfigurationProperties record에 @Validated를 붙이면 검증이 어떻게 동작하는가?

참고

커스텀 자동 구성 만들기

외부 라이브러리를 Spring Boot에 통합할 때, 자동 구성을 직접 만들 수 있다:

// Spring Boot 4 / Java 25 — 커스텀 자동 구성
@AutoConfiguration
@ConditionalOnClass(RedisClient.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "app.redis", name = "enabled", havingValue = "true", matchIfMissing = true)
    public RedisClient redisClient(RedisProperties props) {
        return RedisClient.create(props.getHost(), props.getPort());
    }
}
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.redis.RedisAutoConfiguration

커스텀 자동 구성을 만들면, app.redis.enabled=true만 설정하면 RedisClient bean이 자동 등록된다. 사용자가 직접 @Bean으로 정의하면 자동 구성이 물러난다 (@ConditionalOnMissingBean).

  1. Spring Boot 4.0과 이전 버전(Spring Boot 3.x)의 가장 큰 차이점은 무엇인가? 마이그레이션 시 주의할 점은?
  2. 이 글에서 다룬 개념을 실제 프로젝트에 적용할 때 가장 먼저 고려해야 할 것은?

'Develop Artifacts > Spring Boot' 카테고리의 다른 글

SpringBoot - 06. testing  (0) 2026.07.12
SpringBoot - 05. spring-data-jpa  (0) 2026.07.12
SpringBoot - 4. rest api  (0) 2026.07.12
SpringBoot - 03. embedded-server  (0) 2026.07.12
SpringBoot - 02. starter-config  (0) 2026.07.12