Spring에서는 특정 조건에 따라 빈을 생성하거나 설정을 적용할 수 있도록 다양한 @Conditional 어노테이션을 제공합니다. 이를 통해 유연하고 조건에 맞는 구성(Configurations)을 설정할 수 있습니다.
특히 Spring Framework 4.0부터 제공된 @Conditional과 Spring Boot의 확장 기능인 @ConditionalOnXXX 어노테이션들은 Spring Boot 자동 구성(autoconfiguration) 환경에서 더욱 세밀한 조건 설정을 가능하게 해 줍니다.
기본 개념:
용도:
@Conditional(MyCondition.class)
@Bean
public MyService myService() {
return new MyService();
}
위 예제에서 MyService는 MyCondition이 참일 때만 생성됩니다.
| 어노테이션 | 설명 | 비고 |
|---|---|---|
| @ConditionalOnWebApplication | 현재 프로젝트가 웹 애플리케이션 환경일 때 설정이 동작 | 웹 환경에서만 빈 생성 |
| @ConditionalOnBean | 해당 Bean이 Spring Context에 존재할 때 동작 | 자동 구성에만 사용 권장 |
| @ConditionalOnMissingBean | 해당 Bean이 Spring Context에 없을 때 동작 | 자동 구성에만 사용 권장 |
| @ConditionalOnClass | 특정 클래스가 클래스패스에 존재할 때 설정이 동작 | 특정 라이브러리 의존성 조건 설정 |
| @ConditionalOnMissingClass | 특정 클래스가 클래스패스에 없을 때 설정이 동작 | |
| @ConditionalOnResource | 특정 자원(e.g., 파일)이 존재할 때 설정이 동작 | 파일 등의 자원 조건 설정 |
| @ConditionalOnProperty | 특정 프로퍼티가 설정되어 있을 때 동작 | 설정된 프로퍼티 조건 확인 |
| @ConditionalOnJava | JVM 버전에 따라 동작 여부 결정 | 특정 Java 버전 조건 |
| @ConditionalOnWarDeployment | 전통적인 WAR 배포 방식에서만 동작 | |
| @ConditionalOnExpression | SpEL(Spring Expression Language) 표현식의 결과에 따라 동작 | 조건이 복잡할 때 유용 |
전통적인 WAR 배포 방식일 때만 설정을 적용합니다. 톰캣이나 제티와 같은 외부 WAS에서 실행될 때만 활성화해야 할 빈이 있을 경우 유용합니다.
예제 코드: @ConditionalOnProperty와 @ConditionalOnClass 사용
@Configuration
public class MyAutoConfiguration {
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
@Bean
public FeatureService featureService() {
return new FeatureService();
}
@ConditionalOnClass(name = "com.example.SomeLibrary")
@Bean
public LibraryService libraryService() {
return new LibraryService();
}
}
위 예제에서:
이러한 조건부 어노테이션들은 자동 구성을 더욱 세밀하게 조정하고, 불필요한 빈 생성을 줄이며, 의존성 관리와 리소스 최적화에도 도움을 줍니다.
@ConditionalOnClass와 @ConditionalOnMissingClass는 특정 모듈이나 라이브러리가 클래스패스에 존재하는지 여부를 확인하여 조건에 맞는 설정을 적용할 수 있습니다.
예를 들어, 여러 기능을 모듈 단위로 나누어 각 모듈이 개별적인 라이브러리를 필요로 한다면, 해당 라이브러리가 클래스패스에 존재할 때만 모듈을 활성화하는 방식으로 의존성을 관리할 수 있습니다.
예시: 예를 들어, AWS 관련 기능을 제공하는 모듈이 aws-java-sdk 라이브러리에 의존할 때, @ConditionalOnClass(name = "com.amazonaws.services.s3.AmazonS3")를 사용하여 aws-java-sdk가 포함된 경우에만 AWS 관련 빈을 활성화할 수 있습니다.
이는 모듈 간 결합도를 낮추고, 불필요한 빈 생성 및 의존성 오류를 방지하는 데 도움이 됩니다.
@ConditionalOnProperty는 주로 application.properties 또는 application.yml 파일의 프로퍼티 설정에 따라 빈을 활성화하거나 비활성화합니다. 이를 효과적으로 관리하려면 다음 사항을 고려해야 합니다.
기본값 설정: 필수적인 설정이 아닐 경우 havingValue나 matchIfMissing 속성을 사용하여 기본값을 설정합니다. 예를 들어, matchIfMissing = true를 설정하면 프로퍼티가 누락되어도 기본적으로 빈이 생성됩니다.
환경 분리: 개발, 테스트, 운영 환경별로 필요한 설정만 활성화하도록 application-{profile}.properties 파일을 활용하여 프로파일 기반 설정을 관리합니다.
명확한 프로퍼티 이름: 프로퍼티 이름은 기능의 목적을 명확히 설명할 수 있도록 합니다. 예를 들어, featureX.enabled와 같은 이름을 사용하면 해당 프로퍼티가 기능 활성화 여부와 관련된 것임을 쉽게 파악할 수 있습니다.
설정 문서화: 프로퍼티 사용에 대한 설명을 코드 주석 또는 문서에 포함하여 다른 개발자들이 각 프로퍼티의 역할과 기본값을 이해할 수 있도록 합니다.
@ConditionalOnExpression은 SpEL(Spring Expression Language)을 사용하여 복잡한 조건을 정의할 수 있지만, 다음 사항을 고려하여 사용해야 합니다.
간단한 표현 유지: 표현식이 복잡해질수록 가독성과 유지보수가 어려워지므로, 가능한 한 간단하게 표현식을 작성합니다. 예를 들어, @ConditionalOnExpression("${featureA.enabled} and ${featureB.enabled}")처럼 직관적인 표현을 사용합니다.
성능 최적화: SpEL은 런타임 평가가 필요하므로 복잡한 조건은 성능에 영향을 줄 수 있습니다. 이 경우 SpEL을 최소한으로 사용하고, 불필요한 표현식을 피합니다.
대체 옵션 검토: 표현식이 지나치게 복잡하거나 자주 변경될 가능성이 있으면, @ConditionalOnProperty나 다른 단순한 조건부 어노테이션으로 대체하는 것이 좋습니다.
주석과 문서화: 복잡한 조건이 불가피한 경우, 표현식에 대한 설명을 코드에 주석으로 추가하여 다른 개발자가 이해할 수 있도록 합니다.
이와 같은 점들을 고려하면 @ConditionalOnExpression을 더욱 효과적이고 안정적으로 사용할 수 있습니다.
예시:
@ConditionalOnExpression("${featureX.enabled} and ${featureY.enabled}")
@Bean
public FeatureService featureService() {
return new FeatureService();
}
이 예시에서, featureX와 featureY가 모두 활성화된 경우에만 featureService 빈이 생성됩니다.