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가 시작되면:
- 자동 구성 클래스 발견: 모든 JAR의
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports파일을 읽는다. Spring Boot 4.0의 모듈화 구조에서는 각 기능 모듈(data-jpa, web, security)이 자신의imports파일을 가진다. - 조건 평가: 각 자동 구성 클래스의
@Conditional어노테이션을 평가한다.@ConditionalOnClass(DataSource.class)는ClassLoader에DataSource클래스가 있는지 확인한다 — 있으면 통과, 없으면 그 자동 구성 클래스 전체를 건너뛴다. - 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 친화적.
생각해 볼 문제
@ConditionalOnMissingBean이@Bean순서에 의존하면 어떤 문제가 발생하는가? Spring Boot 4에서 어떻게 해결하는가?@AutoConfiguration과@Configuration의 차이는 무엇인가? 자동 구성 클래스는 왜 별도 어노테이션이 필요한가?- GraalVM native image 환경에서 자동 구성의 조건 평가가 어떻게 달라지는가? (AOT 처리)
- Spring Boot 4에서
spring.factories파일이 완전히 제거됐다면, 레거시 라이브러리는 어떻게 호환되는가? @ConfigurationPropertiesrecord에@Validated를 붙이면 검증이 어떻게 동작하는가?
참고
- Spring Boot 4.0 Reference - Auto-configuration - 접근 2026-07-10
- Spring Boot 4.0 Release - 접근 2026-07-10
- Spring Boot 4.0 - Developing Auto-configuration - 접근 2026-07-10
- Spring Framework 7 - @Conditional - 접근 2026-07-10
커스텀 자동 구성 만들기
외부 라이브러리를 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만 설정하면RedisClientbean이 자동 등록된다. 사용자가 직접@Bean으로 정의하면 자동 구성이 물러난다 (@ConditionalOnMissingBean).
- Spring Boot 4.0 - Auto-configuration Order - 접근 2026-07-10
- Spring Boot 4.0과 이전 버전(Spring Boot 3.x)의 가장 큰 차이점은 무엇인가? 마이그레이션 시 주의할 점은?
- 이 글에서 다룬 개념을 실제 프로젝트에 적용할 때 가장 먼저 고려해야 할 것은?
- Spring Framework 7 Reference - 접근 2026-07-10
- Jakarta EE 11 Specification - 접근 2026-07-10
'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 |
