Auto-Configuration — 스프링부트는 설정 없이 어떻게 동작할까
스프링부트로 프로젝트를 만들면 DataSource도, JdbcTemplate도, 웹 서버도 자동으로 설정됩니다. 아무 설정도 하지 않았는데 어떻게 이게 가능할까요?
개념 정의
Auto-Configuration 은 스프링부트가 클래스패스에 있는 라이브러리와 이미 정의된 빈을 기반으로 필요한 설정을 자동으로 적용하는 메커니즘입니다. "관례가 설정보다 우선한다(Convention over Configuration)"는 원칙의 핵심 구현체입니다.
왜 필요한가
스프링 프레임워크만 사용하면 이런 설정을 직접 해야 합니다.
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
ds.setUsername("root");
ds.setPassword("password");
ds.setMaximumPoolSize(10);
return ds;
}
이어서 @Bean을 적용한 나머지 구현부입니다.
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
스프링부트의 Auto-Configuration이 있으면 application.yml에 URL만 적으면 됩니다. 나머지는 자동입니다.
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
내부 동작
전체 흐름
Auto-Configuration이 빈을 등록하기까지의 과정은 다음과 같습니다.
@SpringBootApplication안에@EnableAutoConfiguration이 포함되어 있습니다.AutoConfigurationImportSelector가AutoConfiguration.imports파일에서 자동 설정 클래스 목록(약 150개)을 읽습니다.- 각 클래스의
@Conditional조건을 평가합니다 — 클래스패스에 해당 라이브러리가 있는지, 사용자가 이미 빈을 등록했는지 등. - 조건을 통과한 클래스만 빈으로 등록됩니다.
이 과정 덕분에 spring-boot-starter-web을 의존성에 추가하면 Tomcat, DispatcherServlet, Jackson이 자동으로 설정됩니다.
@Conditional 시리즈
Auto-Configuration의 핵심은 조건부 로딩입니다.
@ConditionalOnClass(DataSource.class)
// DataSource 클래스가 클래스패스에 있을 때 (라이브러리가 의존성에 포함)
@ConditionalOnMissingClass("com.example.SomeClass")
// 특정 클래스가 클래스패스에 없을 때
@ConditionalOnBean(DataSource.class)
// DataSource 타입의 빈이 이미 등록되어 있을 때
@ConditionalOnMissingBean(DataSource.class)
// DataSource 타입의 빈이 아직 없을 때
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
// 특정 프로퍼티가 특정 값일 때
@ConditionalOnWebApplication(type = Type.SERVLET)
// 서블릿 웹 애플리케이션일 때
@ConditionalOnResource(resources = "classpath:schema.sql")
// 특정 리소스 파일이 존재할 때
실제 Auto-Configuration 클래스 예시
// DataSourceAutoConfiguration (개념적 구조)
@AutoConfiguration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(DataSource.class) // 사용자가 직접 등록하면 적용 안 됨
@ConditionalOnProperty(name = "spring.datasource.url")
static class PooledDataSourceConfiguration {
이어서 @Bean을 적용한 나머지 구현부입니다.
@Bean
@ConditionalOnMissingBean
DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
}
}
핵심 패턴: @ConditionalOnMissingBean → 사용자가 직접 빈을 등록하면 Auto-Configuration은 물러남
코드 예제
Auto-Configuration 디버깅
# 방법 1: 커맨드라인
java -jar app.jar --debug
# 방법 2: application.yml
debug: true
출력 결과:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes 'javax.sql.DataSource',
'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'
Negative matches:
-----------------
RabbitAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class
'com.rabbitmq.client.Channel'
자동 설정 오버라이드 (사용자 설정 우선)
@Configuration
public class MyDataSourceConfig {
@Bean
public DataSource dataSource() {
// 사용자가 직접 DataSource를 등록하면
// DataSourceAutoConfiguration의 DataSource 빈은 생성되지 않음
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://custom-server:3306/mydb");
ds.setMaximumPoolSize(50); // 커스텀 설정
return ds;
}
}
특정 Auto-Configuration 비활성화
// 방법 1: 어노테이션으로 제외
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
SecurityAutoConfiguration.class
})
public class MyApplication { ... }
// 방법 2: 프로퍼티로 제외
// application.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
커스텀 Auto-Configuration 만들기
// 1. 자동 설정 클래스 작성
@AutoConfiguration
@ConditionalOnClass(MyLibrary.class)
@EnableConfigurationProperties(MyLibraryProperties.class)
public class MyLibraryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyLibraryClient myLibraryClient(MyLibraryProperties properties) {
return new MyLibraryClient(properties.getApiKey(), properties.getTimeout());
}
}
이어서 나머지 구현 부분입니다.
// 2. 프로퍼티 클래스
@ConfigurationProperties(prefix = "mylib")
public class MyLibraryProperties {
private String apiKey;
private Duration timeout = Duration.ofSeconds(30);
// getter, setter
}
// 3. META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.MyLibraryAutoConfiguration
# 사용자가 설정만 넣으면 자동으로 MyLibraryClient 빈이 생성됨
mylib:
api-key: my-api-key
timeout: 10s
Auto-Configuration 순서 제어
@AutoConfiguration(
after = DataSourceAutoConfiguration.class, // DataSource 이후에 실행
before = JpaRepositoriesAutoConfiguration.class // JPA Repository 이전에 실행
)
public class MyAutoConfiguration { ... }
Actuator로 Auto-Configuration 확인
# application.yml
management:
endpoints:
web:
exposure:
include: conditions
GET /actuator/conditions를 호출하면 어떤 Auto-Configuration이 적용되었고 왜 적용(또는 미적용)되었는지 JSON으로 확인할 수 있습니다.
주의할 점
1. 의존성만 추가했는데 의도치 않은 자동 설정이 활성화된다
spring-boot-starter-data-jpa를 추가하면 DataSource, EntityManagerFactory, TransactionManager가 자동으로 구성됩니다. DB 접속 정보 없이 이 의존성을 추가하면 Failed to configure a DataSource 에러로 애플리케이션이 시작되지 않습니다. 아직 DB를 사용하지 않는데 의존성만 미리 넣어두면 이런 문제가 발생하므로, @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)로 명시적으로 제외해야 합니다.
2. 사용자 빈과 자동 설정 빈의 우선순위를 모르면 설정이 무시된다
@ConditionalOnMissingBean 덕분에 사용자가 직접 등록한 빈이 우선하지만, 빈 타입이 정확히 일치해야 합니다. 예를 들어 자동 설정이 ObjectMapper 타입을 체크하는데 사용자가 서브클래스를 등록하면 자동 설정이 추가로 적용되어 빈이 2개가 됩니다. --debug 플래그로 CONDITIONS EVALUATION REPORT를 확인하여 어떤 자동 설정이 적용되었는지 반드시 검증해야 합니다.
3. spring.factories에서 AutoConfiguration.imports로의 마이그레이션을 놓치면 자동 설정이 동작하지 않는다
Spring Boot 3.0부터 자동 설정 등록 방식이 META-INF/spring.factories에서 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports로 변경되었습니다. Spring Boot 2에서 3으로 업그레이드할 때 커스텀 스타터의 등록 파일을 변경하지 않으면 자동 설정이 무시되어, 빈이 등록되지 않는데 에러 메시지도 없어 원인 파악이 어렵습니다.
Boot 4.0에서의 Auto-Configuration 변경사항
Boot 4.0(Spring Framework 7)에서는 Auto-Configuration에 몇 가지 변화가 있습니다.
@AutoConfiguration 필수화
Boot 3.x에서는 @Configuration + AutoConfiguration.imports 등록만으로 자동 설정이 동작했지만, Boot 4.0부터는 ** 반드시 @AutoConfiguration을 사용 **해야 합니다. @Configuration만으로는 자동 설정으로 인식되지 않습니다.
// Boot 3.x — @Configuration도 동작했음
@Configuration
@ConditionalOnClass(MyLibrary.class)
public class MyAutoConfig { ... }
// Boot 4.0 — @AutoConfiguration 필수
@AutoConfiguration
@ConditionalOnClass(MyLibrary.class)
public class MyAutoConfig { ... }
조건부 어노테이션 개선
Boot 4.0에서 @ConditionalOnThreading이 추가되어 Virtual Threads 활성화 여부에 따라 자동 설정을 분기할 수 있습니다.
@AutoConfiguration
@ConditionalOnThreading(Threading.VIRTUAL)
public class VirtualThreadTaskExecutorAutoConfiguration {
// Virtual Threads가 활성화된 경우에만 적용되는 설정
}
Boot 4.0으로 마이그레이션할 때, 커스텀 Auto-Configuration 클래스의 어노테이션을
@AutoConfiguration으로 변경하는 것을 잊지 마세요. 자세한 내용은 Spring Boot 4.0 마이그레이션 가이드를 참고해 주세요.
정리
| 항목 | 설명 |
|---|---|
| 동작 원리 | 클래스패스 + @Conditional 조건으로 빈 자동 등록 |
| 사용자 우선 | @ConditionalOnMissingBean — 사용자 빈이 항상 우선 |
| 디버깅 | --debug 플래그로 CONDITIONS EVALUATION REPORT 확인 |
| 비활성화 | @SpringBootApplication(exclude = ...) |
| 등록 파일 | Spring Boot 3+: AutoConfiguration.imports |
| Boot 4.0 | @AutoConfiguration 필수, @ConditionalOnThreading 추가 |