Auto-Configuration이란?
Spring Boot의 마법 같은 “설정 없이 동작”은 Auto-Configuration 덕분이다. 클래스패스에 라이브러리가 있으면 자동으로 Bean을 등록하고, application.yml 프로퍼티로 동작을 튜닝한다. 이 메커니즘의 핵심이 @Conditional 어노테이션 패밀리다. 자체 스타터 라이브러리를 만들거나 조건부 Bean 등록을 제어하려면 반드시 이해해야 한다.
@Conditional 어노테이션 종류
| 어노테이션 | 조건 | 예시 |
|---|---|---|
@ConditionalOnClass |
클래스패스에 특정 클래스 존재 | Redis 라이브러리가 있을 때만 |
@ConditionalOnMissingClass |
클래스패스에 특정 클래스 없음 | 폴백 구현 등록 |
@ConditionalOnBean |
특정 Bean이 이미 등록됨 | DataSource가 있을 때만 |
@ConditionalOnMissingBean |
특정 Bean이 없음 | 사용자 커스텀 Bean 우선 |
@ConditionalOnProperty |
프로퍼티 값 조건 | feature flag 활성화 시 |
@ConditionalOnExpression |
SpEL 표현식 평가 | 복합 조건 |
@ConditionalOnResource |
리소스 파일 존재 | 설정 파일이 있을 때만 |
@ConditionalOnWebApplication |
웹 애플리케이션 타입 | Servlet/Reactive 구분 |
@ConditionalOnProperty 심화
가장 자주 사용되는 조건이다. Feature Flag, 환경별 설정 분기에 핵심적이다.
// 기본 사용: 프로퍼티가 "true"일 때만 Bean 등록
@Configuration
@ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new RedisCacheManager(...);
}
}
// matchIfMissing: 프로퍼티가 없어도 기본 활성화
@ConditionalOnProperty(
name = "app.metrics.enabled",
havingValue = "true",
matchIfMissing = true // 프로퍼티 미설정 시 true로 간주
)
public class MetricsConfig { }
// prefix로 그룹화
@ConditionalOnProperty(
prefix = "app.notification",
name = "type",
havingValue = "slack"
)
public class SlackNotificationConfig { }
@ConditionalOnProperty(
prefix = "app.notification",
name = "type",
havingValue = "email"
)
public class EmailNotificationConfig { }
# application.yml
app:
cache:
enabled: true
notification:
type: slack # slack → SlackNotificationConfig 활성화
metrics:
# 미설정 → matchIfMissing=true이므로 MetricsConfig 활성화
@ConditionalOnMissingBean 패턴
Auto-Configuration의 핵심 패턴이다. “사용자가 직접 정의한 Bean이 없을 때만 기본 Bean을 등록”하는 방식으로, 커스터마이징 포인트를 제공한다.
@Configuration
public class ObjectMapperAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 사용자가 ObjectMapper를 직접 등록하면 이 Bean은 무시
public ObjectMapper objectMapper() {
return new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}
// 사용자 프로젝트에서 커스텀 ObjectMapper 등록
@Configuration
public class CustomConfig {
@Bean
public ObjectMapper objectMapper() {
// 이 Bean이 우선 → Auto-Configuration의 ObjectMapper는 등록 안 됨
return new ObjectMapper()
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}
}
Spring Boot의 거의 모든 Auto-Configuration이 이 패턴을 따른다. HikariCP DataSource, RestTemplate, WebClient 등 기본 Bean이 @ConditionalOnMissingBean으로 보호된다.
커스텀 Starter 만들기
팀 공통 라이브러리를 Spring Boot Starter로 만들면 의존성 추가만으로 자동 설정이 적용된다.
1단계: Auto-Configuration 클래스
// my-audit-spring-boot-starter
@Configuration
@ConditionalOnClass(AuditService.class)
@EnableConfigurationProperties(AuditProperties.class)
public class AuditAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "audit.enabled", havingValue = "true", matchIfMissing = true)
public AuditService auditService(AuditProperties properties) {
return new AuditService(properties.getStorageType(), properties.getRetentionDays());
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(AuditService.class)
public AuditInterceptor auditInterceptor(AuditService auditService) {
return new AuditInterceptor(auditService);
}
}
@ConfigurationProperties(prefix = "audit")
@Getter @Setter
public class AuditProperties {
private boolean enabled = true;
private String storageType = "database";
private int retentionDays = 90;
}
2단계: spring.factories 또는 AutoConfiguration.imports
# Spring Boot 2.x: META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.example.audit.AuditAutoConfiguration
# Spring Boot 3.x: META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.audit.AuditAutoConfiguration
3단계: 사용하는 프로젝트
<!-- pom.xml에 의존성만 추가하면 끝 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>my-audit-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
# application.yml — 필요 시 튜닝
audit:
storage-type: elasticsearch
retention-days: 180
@Conditional 조합
여러 조건을 조합해 정교한 분기가 가능하다.
@Configuration
@ConditionalOnClass(RedisConnectionFactory.class) // Redis 라이브러리 존재
@ConditionalOnProperty(name = "app.cache.type", havingValue = "redis") // redis 타입
public class RedisCacheConfig {
@Bean
@ConditionalOnMissingBean(CacheManager.class) // 사용자 정의 없을 때만
@ConditionalOnBean(RedisConnectionFactory.class) // 커넥션 팩토리 존재 시
public CacheManager redisCacheManager(RedisConnectionFactory factory) {
return RedisCacheManager.builder(factory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30)))
.build();
}
}
// SpEL 복합 조건
@Bean
@ConditionalOnExpression(
"${app.feature.v2:false} and '${spring.profiles.active}'.contains('prod')"
)
public FeatureV2Service featureV2Service() {
return new FeatureV2Service();
}
커스텀 @Conditional 구현
기본 제공 어노테이션으로 부족하면 직접 만들 수 있다.
// 특정 OS에서만 활성화
public class OnLinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String os = context.getEnvironment().getProperty("os.name", "").toLowerCase();
return os.contains("linux");
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnLinuxCondition.class)
public @interface ConditionalOnLinux {}
// 사용
@Bean
@ConditionalOnLinux
public FileWatcher linuxFileWatcher() {
return new InotifyFileWatcher();
}
디버깅: Auto-Configuration 리포트
# 어떤 Auto-Configuration이 적용/제외되었는지 확인
java -jar app.jar --debug
# 또는 application.yml
debug: true
logging:
level:
org.springframework.boot.autoconfigure: DEBUG
# Actuator로 확인
# GET /actuator/conditions
{
"positiveMatches": {
"DataSourceAutoConfiguration": [{
"condition": "OnClassCondition",
"message": "@ConditionalOnClass found required classes"
}]
},
"negativeMatches": {
"MongoAutoConfiguration": {
"notMatched": [{
"condition": "OnClassCondition",
"message": "@ConditionalOnClass did not find required class"
}]
}
}
}
/actuator/conditions 엔드포인트는 모든 @Conditional 평가 결과를 보여준다. Auto-Configuration이 왜 적용됐는지, 왜 안 됐는지 한눈에 확인할 수 있다. Actuator 운영 가이드도 참고하자.
Auto-Configuration 순서 제어
@AutoConfiguration(
after = DataSourceAutoConfiguration.class,
before = FlywayAutoConfiguration.class
)
@ConditionalOnBean(DataSource.class)
public class MyDbMigrationAutoConfiguration {
// DataSource 설정 후, Flyway 전에 실행
}
정리
| 패턴 | 용도 |
|---|---|
@ConditionalOnProperty |
Feature Flag, 환경별 분기 |
@ConditionalOnMissingBean |
기본값 제공 + 커스터마이징 허용 |
@ConditionalOnClass |
선택적 의존성 지원 |
| 커스텀 Starter | 팀 공통 설정 배포 |
@Conditional을 이해하면 Spring Boot의 자동 설정 마법이 투명해진다. 커스텀 Starter를 만들어 팀 공통 설정을 의존성 하나로 배포하고, @ConditionalOnMissingBean으로 확장 포인트를 열어두자.