Spring Boot 자동 설정 원리, “어노테이션 하나 붙였을 뿐인데 왜 DB 연결이 되고, 톰캣이 뜨고, 시큐리티가 걸리는 거지?”라는 의문을 한 번쯤 품어보셨다면 이 글이 그 답을 드립니다. @SpringBootApplication 안에 조용히 앉아있는 @EnableAutoConfiguration, 이것이 Spring Boot 마법의 진짜 열쇠입니다. 개념만 알고 지나치면 자동 설정이 예상대로 동작하지 않을 때, 혹은 커스텀 설정이 자동 설정과 충돌할 때 속수무책이 됩니다. 이 글에서는 소스 코드를 직접 열어가며 @EnableAutoConfiguration이 클래스패스를 어떻게 분석하고, 수백 개의 후보 중 어떤 조건으로 설정을 골라 빈을 등록하는지 단계별로 완전히 해부합니다. 끝까지 읽고 나면 자동 설정을 자유자재로 제어하고 나만의 AutoConfiguration도 직접 만들 수 있습니다.
목차
- Spring Boot 자동 설정이란 무엇인가 – 기초 개념 정리
- Spring Boot 자동 설정 원리 – 내부 동작 단계별 분석
- @Conditional 시리즈 – 조건부 설정 등록의 핵심
- 자동 설정 충돌과 오작동 – 주의점과 디버깅 방법
- 실전 단계별 활용법 – 자동 설정 제어와 커스텀 구현
- 전문가 관점 – Spring Boot 3.x 변화와 추천 학습 도구
1. Spring Boot 자동 설정이란 무엇인가 – 기초 개념 정리
자동 설정(Auto Configuration) 은 Spring Boot가 클래스패스에 존재하는 라이브러리를 분석하여 개발자가 명시적으로 설정하지 않아도 필요한 빈을 자동으로 등록하는 메커니즘입니다. Spring Boot의 핵심 철학인 “Convention over Configuration(설정보다 관습)” 을 구현하는 기술적 기반입니다.
자동 설정이 없었던 시절 – Spring Framework의 번거로움
Spring Boot 이전, 순수 Spring Framework에서 웹 애플리케이션을 구성하려면 이런 설정 코드를 매번 직접 작성해야 했습니다.
java
// Spring Framework 시절 – 모든 설정을 직접 작성
@Configuration
@EnableWebMvc
@ComponentScan("com.example")
public class WebConfig implements WebMvcConfigurer {
// ViewResolver 직접 등록
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
// MessageConverter 직접 등록
@Bean
public MappingJackson2HttpMessageConverter jacksonConverter() {
return new MappingJackson2HttpMessageConverter(new ObjectMapper());
}
// DataSource 직접 등록
@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;
}
// TransactionManager 직접 등록
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
Spring Boot에서는 이 모든 설정이 @SpringBootApplication 하나와 application.yml 몇 줄로 대체됩니다. 이것이 가능한 이유가 바로 자동 설정입니다.
자동 설정의 세 가지 핵심 구성 요소
Spring Boot 자동 설정 원리는 세 가지 핵심 요소가 맞물려 동작합니다.
① @EnableAutoConfiguration
└── 자동 설정 메커니즘을 활성화하는 트리거 어노테이션
② AutoConfigurationImportSelector
└── AutoConfiguration 후보 클래스 목록을 읽어 조건 평가 후 등록할 클래스 선별
③ @Conditional 시리즈
└── 클래스패스·빈 존재·프로퍼티 값 등을 기준으로 설정 적용 여부 결정
이 세 요소가 어떻게 동작하는지 소스 코드를 열어서 단계별로 살펴보겠습니다.
2. Spring Boot 자동 설정 원리 – 내부 동작 단계별 분석
@EnableAutoConfiguration 소스 코드 분석
java
// org.springframework.boot.autoconfigure.EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // ← ①
@Import(AutoConfigurationImportSelector.class) // ← ② 핵심
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY =
"spring.boot.enableautoconfiguration";
// 제외할 AutoConfiguration 클래스 직접 지정
Class<?>[] exclude() default {};
// 클래스 이름 문자열로 제외 지정 (클래스가 없어도 사용 가능)
String[] excludeName() default {};
}
@AutoConfigurationPackage는 메인 클래스가 위치한 패키지를 Spring의 기본 컴포넌트 스캔 패키지로 등록합니다. 그리고 진짜 핵심은 @Import(AutoConfigurationImportSelector.class)입니다. 이 한 줄이 자동 설정 전체를 작동시킵니다.
AutoConfigurationImportSelector 동작 흐름
AutoConfigurationImportSelector는 ImportSelector 인터페이스를 구현하며, selectImports() 메서드에서 적용할 AutoConfiguration 클래스 목록을 반환합니다.
java
// AutoConfigurationImportSelector 핵심 로직 (단순화)
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware,
Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// AutoConfiguration 후보 목록 로드 및 필터링
AutoConfigurationEntry autoConfigurationEntry =
getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(
AnnotationMetadata annotationMetadata) {
// ① 후보 클래스 전체 목록 로드
List<String> configurations = getCandidateConfigurations(
annotationMetadata, attributes);
// ② 중복 제거
configurations = removeDuplicates(configurations);
// ③ exclude 속성으로 지정된 클래스 제거
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
configurations.removeAll(exclusions);
// ④ @Conditional 조건 필터링 (핵심!)
configurations = getConfigurationClassFilter()
.filter(configurations);
return new AutoConfigurationEntry(configurations, exclusions);
}
protected List<String> getCandidateConfigurations(
AnnotationMetadata metadata, AnnotationAttributes attributes) {
// Spring Boot 3.x: AutoConfiguration.imports 파일에서 로드
List<String> configurations = ImportCandidates.load(
AutoConfiguration.class, getBeanClassLoader()).getCandidates();
// 후보 목록이 비어있으면 경고
Assert.notEmpty(configurations,
"No auto configuration classes found in " +
"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports");
return configurations;
}
}
AutoConfiguration.imports 파일 구조
Spring Boot 3.x에서 자동 설정 후보 클래스들은 다음 경로 파일에 등록됩니다.
META-INF/spring/
org.springframework.boot.autoconfigure.AutoConfiguration.imports
실제 파일 내용은 다음과 같이 적용할 AutoConfiguration 클래스들이 한 줄씩 나열됩니다.
# 실제 AutoConfiguration.imports 파일 내용 일부 (Spring Boot 3.x)
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
# ... 150개 이상의 AutoConfiguration 클래스
Spring Boot 2.x vs 3.x 변화: Spring Boot 2.x까지는
META-INF/spring.factories파일의org.springframework.boot.autoconfigure.EnableAutoConfiguration키 아래에 자동 설정 클래스를 등록했습니다. Spring Boot 3.x부터는 전용AutoConfiguration.imports파일로 분리되어 로딩 성능과 명확성이 개선되었습니다.
자동 설정 처리 전체 파이프라인
[애플리케이션 시작]
│
▼
@SpringBootApplication
└── @EnableAutoConfiguration 활성화
│
▼
AutoConfigurationImportSelector.selectImports() 호출
│
▼
┌─────────────────────────────────────────┐
│ AutoConfiguration.imports 파일 읽기 │
│ → 150개+ 후보 클래스 목록 수집 │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ exclude 속성 처리 │
│ → 개발자가 명시적으로 제외한 클래스 제거│
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ @Conditional 조건 평가 (핵심 필터링) │
│ ┌─────────────────────────────────┐ │
│ │ @ConditionalOnClass │ │
│ │ 클래스패스에 특정 클래스 존재? │ │
│ ├─────────────────────────────────┤ │
│ │ @ConditionalOnMissingBean │ │
│ │ 특정 빈이 아직 없음? │ │
│ ├─────────────────────────────────┤ │
│ │ @ConditionalOnProperty │ │
│ │ 특정 프로퍼티 값 일치? │ │
│ └─────────────────────────────────┘ │
│ → 조건 통과한 AutoConfiguration만 선별│
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 선별된 AutoConfiguration 클래스들 │
│ BeanDefinition으로 등록 │
│ → 빈 생성 및 의존성 주입 │
└─────────────────────────────────────────┘
│
▼
[애플리케이션 컨텍스트 완성]
실제 AutoConfiguration 클래스 내부 분석
DataSourceAutoConfiguration을 직접 열어보면 자동 설정이 어떻게 구현되는지 패턴이 보입니다.
java
// DataSourceAutoConfiguration 핵심 구조 (단순화)
@AutoConfiguration(before = SqlInitializationAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
// 클래스패스에 DataSource가 있을 때만 이 설정 전체가 활성화
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
// R2DBC가 없을 때만 (반응형 프로젝트와 충돌 방지)
@EnableConfigurationProperties(DataSourceProperties.class)
// application.yml의 spring.datasource.* 속성을 DataSourceProperties에 바인딩
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceCheckpointRestoreConfiguration.class })
public class DataSourceAutoConfiguration {
// 내장 DB(H2, HSQL, Derby) 자동 설정 내부 클래스
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
// 개발자가 DataSource를 직접 등록하지 않았을 때만
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {}
// 커넥션 풀(HikariCP 등) 설정 내부 클래스
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class,
DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class,
DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
@Bean
@ConditionalOnMissingBean(JdbcConnectionDetails.class)
PropertiesJdbcConnectionDetails jdbcConnectionDetails(
DataSourceProperties properties) {
return new PropertiesJdbcConnectionDetails(properties);
}
}
}
이 코드에서 자동 설정의 핵심 패턴을 확인할 수 있습니다. 클래스 레벨의 @ConditionalOnClass로 전체 자동 설정의 적용 여부를 결정하고, 메서드·내부 클래스 레벨의 @ConditionalOnMissingBean으로 개발자가 직접 등록한 빈이 있으면 자동 설정이 스스로 물러납니다. 이것이 Spring Boot 자동 설정이 오버라이드 가능한 이유입니다.
3. @Conditional 시리즈 – 조건부 설정 등록의 핵심
@Conditional은 Spring Boot 자동 설정 원리의 심장부입니다. 조건이 충족될 때만 해당 빈 또는 설정 클래스를 등록하도록 제어합니다.
주요 @Conditional 어노테이션 완전 정리
① @ConditionalOnClass / @ConditionalOnMissingClass
java
// 클래스패스에 특정 클래스가 있을 때만 설정 활성화
@ConditionalOnClass(RedisOperations.class)
// → spring-data-redis 의존성 추가 시 RedisOperations가 클래스패스에 존재
// → 조건 충족 → Redis 자동 설정 활성화
@ConditionalOnMissingClass("com.mongodb.MongoClient")
// → MongoClient가 클래스패스에 없을 때만 이 설정 활성화
java
// 실제 활용 예시 – Redis AutoConfiguration
@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class,
JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}
② @ConditionalOnMissingBean / @ConditionalOnBean
java
// 가장 많이 쓰이는 패턴 – 개발자가 직접 등록하면 자동 설정이 물러남
@Bean
@ConditionalOnMissingBean(ObjectMapper.class)
// ObjectMapper 빈이 없을 때만 기본 ObjectMapper를 자동 등록
// 개발자가 커스텀 ObjectMapper를 @Bean으로 등록하면 이 자동 설정은 건너뜀
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
return builder.createXmlMapper(false).build();
}
// @ConditionalOnBean – 특정 빈이 있을 때만 활성화
@Bean
@ConditionalOnBean(DataSource.class)
// DataSource 빈이 등록된 경우에만 JdbcTemplate 자동 생성
public JdbcTemplate jdbcTemplate(DataSource dataSource,
JdbcProperties properties) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
JdbcProperties.Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());
return jdbcTemplate;
}
③ @ConditionalOnProperty
java
// application.yml 프로퍼티 값에 따라 설정 활성화 여부 결정
@Bean
@ConditionalOnProperty(
prefix = "spring.cache",
name = "type",
havingValue = "redis", // spring.cache.type=redis 일 때만 활성화
matchIfMissing = false // 프로퍼티가 없으면 비활성화
)
public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
return RedisCacheManager.builder(factory).build();
}
// matchIfMissing = true 활용 예시
@ConditionalOnProperty(
name = "spring.jpa.open-in-view",
havingValue = "true",
matchIfMissing = true // 프로퍼티가 없어도 기본으로 활성화
)
④ @ConditionalOnWebApplication / @ConditionalOnNotWebApplication
java
// 웹 애플리케이션 환경일 때만 활성화 (MVC 또는 Reactive)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// 서블릿 기반 웹 애플리케이션일 때만
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
// 리액티브(WebFlux) 웹 애플리케이션일 때만
@ConditionalOnNotWebApplication
// 웹 애플리케이션이 아닌 경우 (배치, CLI 등)에만
⑤ @ConditionalOnExpression
java
// SpEL(Spring Expression Language) 표현식으로 복잡한 조건 처리
@ConditionalOnExpression(
"${feature.new-payment:false} and '${spring.profiles.active}' != 'test'"
)
// feature.new-payment=true 이고, 프로파일이 test가 아닐 때만 활성화
public NewPaymentService newPaymentService() {
return new NewPaymentService();
}
@Conditional 조건 평가 순서와 우선순위
여러 @Conditional 어노테이션이 함께 선언된 경우 모든 조건을 AND 조건으로 평가합니다. 하나라도 실패하면 해당 빈 또는 설정 클래스는 등록되지 않습니다.
java
@Bean
@ConditionalOnClass(DataSource.class) // 조건 1
@ConditionalOnMissingBean(DataSource.class) // 조건 2
@ConditionalOnProperty( // 조건 3
prefix = "spring.datasource",
name = "url"
)
public DataSource embeddedDataSource() {
// 세 조건을 모두 만족할 때만 이 빈이 등록됨
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
4. 자동 설정 충돌과 오작동 – 주의점과 디버깅 방법
문제 1 – 의도치 않은 자동 설정 활성화
의존성을 추가했을 때 예상치 못한 자동 설정이 함께 활성화되어 애플리케이션이 의도와 다르게 동작할 수 있습니다.
yaml
# 흔한 사례: spring-boot-starter-security 추가 후
# 모든 엔드포인트에 HTTP Basic 인증이 자동 적용됨
# 개발자가 의도하지 않아도 즉시 로그인 화면이 뜨거나
# API 테스트에서 401이 계속 발생
# 해결: 필요하지 않은 자동 설정 명시적 제외
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
- org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
java
// 또는 @SpringBootApplication exclude 속성 사용
@SpringBootApplication(exclude = {
SecurityAutoConfiguration.class,
UserDetailsServiceAutoConfiguration.class
})
public class DemoApplication { ... }
문제 2 – 자동 설정과 수동 설정의 충돌
개발자가 직접 빈을 등록했는데 자동 설정도 같은 타입의 빈을 등록하려 하면 NoUniqueBeanDefinitionException이 발생합니다.
java
// 문제 상황: 개발자가 DataSource를 등록했는데
// DataSourceAutoConfiguration이 또 등록하려 함
@Configuration
public class DatabaseConfig {
// 직접 등록한 DataSource
@Bean
public DataSource primaryDataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/primary");
return ds;
}
}
// DataSourceAutoConfiguration은 @ConditionalOnMissingBean(DataSource.class)가
// 붙어있어 primaryDataSource가 먼저 등록되면 자동으로 물러남
// → 충돌 없음 (이것이 올바른 동작)
// 그러나 아래처럼 빈 이름이 겹치는 경우는 문제가 됨
@Bean
public DataSource dataSource() { // 이름이 자동 설정의 빈 이름과 동일
// 설정에 따라 충돌 또는 오버라이드 발생
...
}
yaml
# Spring Boot 2.1+에서는 기본적으로 빈 오버라이드 금지
# 허용하려면 명시적으로 설정
spring:
main:
allow-bean-definition-overriding: true # 권장하지 않음
문제 3 – 자동 설정 순서 의존성 문제
AutoConfiguration 클래스 간에 순서가 중요한 경우 @AutoConfiguration 어노테이션의 before/after 속성으로 명시해야 합니다.
java
// 올바른 자동 설정 순서 지정
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
// DataSourceAutoConfiguration이 실행된 후에 이 설정 실행
public class FlywayAutoConfiguration {
// DataSource 빈이 이미 등록된 이후 마이그레이션 실행 가능
}
@AutoConfiguration(before = UserDetailsServiceAutoConfiguration.class)
// SecurityAutoConfiguration보다 먼저 실행
public class CustomSecurityAutoConfiguration { ... }
자동 설정 디버깅 – 3가지 방법
방법 1 – debug: true 로 Conditions Evaluation Report 출력
yaml
# application.yml
debug: true
애플리케이션 시작 시 콘솔에 다음과 같은 상세 리포트가 출력됩니다.
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches: ← 활성화된 자동 설정
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes
'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'
(OnClassCondition)
WebMvcAutoConfiguration matched:
- @ConditionalOnClass found required classes
'Servlet', 'DispatcherServlet', 'WebMvcConfigurer' (OnClassCondition)
- @ConditionalOnMissingBean (types: WebMvcConfigurationSupport)
did not find any beans (OnBeanCondition)
Negative matches: ← 비활성화된 자동 설정 (조건 미충족)
-----------------
MongoAutoConfiguration:
- @ConditionalOnClass did not find required class
'com.mongodb.MongoClient' (OnClassCondition)
RedisAutoConfiguration:
- @ConditionalOnClass did not find required class
'org.springframework.data.redis.core.RedisOperations' (OnClassCondition)
Exclusions: ← 명시적으로 제외된 자동 설정
-----------
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
방법 2 – Spring Boot Actuator /actuator/conditions 엔드포인트
yaml
management:
endpoints:
web:
exposure:
include: conditions, beans, env, configprops
bash
# 런타임 자동 설정 조건 평가 결과 조회
curl http://localhost:8080/actuator/conditions | python -m json.tool
방법 3 – IntelliJ IDEA에서 소스 직접 탐색
Shift + Shift (Search Everywhere)
→ "WebMvcAutoConfiguration" 검색
→ @ConditionalOn* 어노테이션 직접 확인
→ 조건을 이해하고 충족/미충족 원인 추론
5. 실전 단계별 활용법 – 자동 설정 제어와 커스텀 구현
Step 1 – 자동 설정 오버라이드: 나만의 빈으로 교체
@ConditionalOnMissingBean 덕분에 직접 빈을 등록하면 자동 설정이 스스로 물러납니다. 이 원리를 활용해 기본 설정을 자유롭게 커스터마이징할 수 있습니다.
java
// ObjectMapper 커스터마이징 – 자동 설정 오버라이드
@Configuration
public class JacksonConfig {
// JacksonAutoConfiguration의 기본 ObjectMapper를 이것으로 대체
@Bean
@Primary
public ObjectMapper customObjectMapper() {
return new ObjectMapper()
// null 필드를 JSON 응답에서 제외
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
// 알 수 없는 필드 무시 (유연한 역직렬화)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
// Java 8 날짜 타입 지원
.registerModule(new JavaTimeModule())
// 날짜를 타임스탬프 숫자 대신 ISO 문자열로
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}
java
// HikariCP 커스터마이징 – DataSourceAutoConfiguration 오버라이드
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setMaximumPoolSize(20);
ds.setMinimumIdle(5);
ds.setConnectionTimeout(30000);
ds.setIdleTimeout(600000);
ds.setMaxLifetime(1800000);
ds.setConnectionTestQuery("SELECT 1");
return ds;
}
}
Step 2 – 나만의 AutoConfiguration 만들기
내부 공통 모듈이나 오픈소스 라이브러리를 만들 때 자동 설정을 직접 구현할 수 있습니다.
java
// Step 2-1: 설정 프로퍼티 클래스
@ConfigurationProperties(prefix = "slack.notification")
@Validated
public class SlackProperties {
@NotEmpty
private String webhookUrl; // 슬랙 웹훅 URL (필수)
private String defaultChannel = "#alerts"; // 기본 채널
private int timeoutSeconds = 5; // HTTP 타임아웃
private boolean enabled = true; // 알림 활성화 여부
// getter, setter...
}
java
// Step 2-2: 자동 설정 클래스
@AutoConfiguration
@ConditionalOnClass(SlackClient.class)
// 클래스패스에 SlackClient가 있을 때만 (slack-sdk 의존성 추가 시)
@ConditionalOnProperty(
prefix = "slack.notification",
name = "webhook-url"
)
// slack.notification.webhook-url이 설정된 경우에만
@EnableConfigurationProperties(SlackProperties.class)
public class SlackNotificationAutoConfiguration {
@Bean
@ConditionalOnMissingBean(SlackNotificationService.class)
// 개발자가 직접 SlackNotificationService를 등록하면 이 자동 설정은 건너뜀
public SlackNotificationService slackNotificationService(
SlackProperties properties) {
return SlackNotificationService.builder()
.webhookUrl(properties.getWebhookUrl())
.defaultChannel(properties.getDefaultChannel())
.timeoutSeconds(properties.getTimeoutSeconds())
.build();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(SlackNotificationService.class)
public SlackHealthIndicator slackHealthIndicator(
SlackNotificationService service) {
// Spring Boot Actuator 헬스 인디케이터 자동 등록
return new SlackHealthIndicator(service);
}
}
java
// Step 2-3: additional-spring-configuration-metadata.json 작성
// IDE 자동완성 지원을 위한 메타데이터
// src/main/resources/META-INF/ 에 위치
{
"properties": [
{
"name": "slack.notification.webhook-url",
"type": "java.lang.String",
"description": "슬랙 인커밍 웹훅 URL"
},
{
"name": "slack.notification.default-channel",
"type": "java.lang.String",
"description": "기본 알림 채널 (기본값: #alerts)",
"defaultValue": "#alerts"
},
{
"name": "slack.notification.enabled",
"type": "java.lang.Boolean",
"description": "슬랙 알림 활성화 여부 (기본값: true)",
"defaultValue": true
}
]
}
# Step 2-4: AutoConfiguration.imports 파일에 등록
# src/main/resources/META-INF/spring/ 에 생성
# 파일명: org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.slack.SlackNotificationAutoConfiguration
java
// Step 2-5: 사용하는 프로젝트에서 의존성만 추가하면 자동 적용
// pom.xml에 slack-notification-spring-boot-starter 추가
// application.yml 설정만 하면 끝
// application.yml
// slack:
// notification:
// webhook-url: https://hooks.slack.com/services/xxx/yyy/zzz
// default-channel: "#dev-alerts"
Step 3 – 프로파일별 자동 설정 제어
java
@Configuration
public class ProfileBasedConfig {
// 개발 환경에서만 H2 콘솔 활성화
@Bean
@Profile("dev")
@ConditionalOnClass(H2ConsoleProperties.class)
public H2ConsoleProperties h2ConsoleProperties() {
H2ConsoleProperties props = new H2ConsoleProperties();
props.setEnabled(true);
props.setPath("/h2-console");
return props;
}
}
yaml
# application-dev.yml – 개발 환경
spring:
h2:
console:
enabled: true
jpa:
show-sql: true
hibernate:
ddl-auto: create-drop
# application-prod.yml – 운영 환경
spring:
h2:
console:
enabled: false # H2 콘솔 비활성화
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration
6. 전문가 관점 – Spring Boot 3.x 변화와 추천 학습 도구
Spring Boot 3.x의 주요 변화
Spring Boot 3.x는 Spring Boot 2.x와 자동 설정 원리는 같지만 몇 가지 중요한 변화가 있습니다.
① spring.factories → AutoConfiguration.imports 분리
[Spring Boot 2.x]
META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
[Spring Boot 3.x]
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
분리 이유는 spring.factories가 AutoConfiguration 외에도 여러 용도로 사용되어 성능과 명확성이 떨어졌기 때문입니다. 3.x에서 AutoConfiguration 전용 파일을 분리하여 로딩 속도와 가독성이 개선되었습니다.
② Jakarta EE 네임스페이스 변경
java
// Spring Boot 2.x (javax.*)
import javax.servlet.Filter;
import javax.persistence.Entity;
// Spring Boot 3.x (jakarta.*)
import jakarta.servlet.Filter;
import jakarta.persistence.Entity;
③ GraalVM Native Image 지원 강화
Spring Boot 3.x는 AOT(Ahead-of-Time) 컴파일과 GraalVM Native Image를 공식 지원합니다. 자동 설정 클래스에 @AutoConfiguration 어노테이션이 도입된 것도 AOT 처리를 위한 변화입니다.
java
// 3.x 이전 – @Configuration 사용
@Configuration(proxyBeanMethods = false)
public class WebMvcAutoConfiguration { ... }
// 3.x 이후 – @AutoConfiguration 사용 (AOT 힌트 포함)
@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration { ... }
Spring Boot 자동 설정 원리 학습을 위한 추천 도구
| 도구 / 리소스 | 용도 |
|---|---|
| IntelliJ IDEA Navigate to Source | AutoConfiguration 클래스 소스 직접 탐색 |
| spring.io/projects/spring-boot GitHub | 최신 AutoConfiguration 소스 확인 |
Spring Boot Actuator /actuator/conditions | 런타임 조건 평가 결과 JSON으로 확인 |
--debug 플래그 | 시작 시 Conditions Evaluation Report 출력 |
| Spring Boot 공식 레퍼런스 (docs.spring.io) | Auto-configuration 챕터 필독 |
| 인프런 김영한 – 스프링 부트 핵심 원리 | 자동 설정 원리 한국어 심화 강의 |
| Baeldung (baeldung.com/spring-boot-autoconfiguration) | 커스텀 AutoConfiguration 영문 실습 가이드 |
면접 대비 핵심 답변
“Spring Boot 자동 설정은 어떻게 동작하나요?” @SpringBootApplication 안의 @EnableAutoConfiguration이 AutoConfigurationImportSelector를 활성화합니다. 이 선택자는 META-INF/spring/AutoConfiguration.imports 파일에서 150개 이상의 후보 AutoConfiguration 클래스를 로드하고, 각 클래스에 붙은 @ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty 등의 조건을 평가하여 조건을 만족하는 클래스만 빈으로 등록합니다.
“자동 설정을 오버라이드하는 방법은?” 두 가지 방법이 있습니다. 첫째, @ConditionalOnMissingBean 덕분에 같은 타입의 빈을 직접 @Bean으로 등록하면 자동 설정이 스스로 물러납니다. 둘째, @SpringBootApplication(exclude = {...}) 또는 spring.autoconfigure.exclude 프로퍼티로 특정 AutoConfiguration을 명시적으로 제외할 수 있습니다.
“@ConditionalOnMissingBean과 @ConditionalOnClass의 차이는?” @ConditionalOnClass는 클래스패스에 특정 클래스가 존재하는지 여부로 활성화를 결정합니다. 주로 특정 라이브러리 의존성 추가 여부에 따라 설정을 켜고 끄는 데 사용합니다. @ConditionalOnMissingBean은 Spring 컨테이너에 특정 타입의 빈이 아직 등록되지 않았을 때만 해당 빈을 등록합니다. 개발자가 직접 빈을 등록하면 자동 설정이 물러나도록 하는 핵심 메커니즘입니다.
결론
Spring Boot 자동 설정 원리는 @EnableAutoConfiguration이 AutoConfigurationImportSelector를 통해 AutoConfiguration.imports 파일의 후보 클래스를 로드하고, @Conditional 시리즈 어노테이션으로 클래스패스·빈 존재·프로퍼티 값을 평가하여 조건을 만족하는 설정만 선별적으로 적용하는 정교한 메커니즘입니다. Spring Boot 자동 설정 원리를 이해하면 예상치 못한 설정 충돌을 스스로 디버깅하고, 자동 설정을 자유롭게 오버라이드하며, 팀 공통 라이브러리에 커스텀 AutoConfiguration을 직접 구현할 수 있습니다. 지금 바로 IntelliJ에서 WebMvcAutoConfiguration을 열어보고, debug: true로 Conditions Evaluation Report를 직접 확인해 보세요. 눈으로 조건 평가 결과를 보는 순간 자동 설정이 완전히 투명해집니다.
답글 남기기