@Conditional

서버란·2024년 11월 5일

스프링

목록 보기
4/4

Spring에서는 특정 조건에 따라 빈을 생성하거나 설정을 적용할 수 있도록 다양한 @Conditional 어노테이션을 제공합니다. 이를 통해 유연하고 조건에 맞는 구성(Configurations)을 설정할 수 있습니다.

특히 Spring Framework 4.0부터 제공된 @Conditional과 Spring Boot의 확장 기능인 @ConditionalOnXXX 어노테이션들은 Spring Boot 자동 구성(autoconfiguration) 환경에서 더욱 세밀한 조건 설정을 가능하게 해 줍니다.

1. @Conditional 어노테이션

기본 개념:

  • Spring Framework 4.0부터 제공되는 @Conditional은 특정 조건에 따라 빈 생성 또는 설정의 적용 여부를 결정합니다.
  • 조건으로 지정된 Condition 인터페이스의 모든 조건이 TRUE로 평가될 때 해당 빈이 활성화됩니다.

용도:

  • @Conditional은 특정 조건에서만 빈이 생성되거나 동작하기를 원할 때 사용됩니다.
  • 빈 구성 또는 생성이 특정 환경에서만 필요할 때 유용합니다.
@Conditional(MyCondition.class)
@Bean
public MyService myService() {
    return new MyService();
}

위 예제에서 MyService는 MyCondition이 참일 때만 생성됩니다.

2. @ConditionalOnXXX 어노테이션

  • Spring Boot는 @Conditional을 확장하여, 다양한 조건별 설정을 보다 세밀하게 제어할 수 있는 @ConditionalOnXXX 어노테이션들을 제공합니다. 이를 통해 Spring Boot의 자동 구성 기능을 더 유연하게 사용할 수 있습니다.
어노테이션설명비고
@ConditionalOnWebApplication현재 프로젝트가 웹 애플리케이션 환경일 때 설정이 동작웹 환경에서만 빈 생성
@ConditionalOnBean해당 Bean이 Spring Context에 존재할 때 동작자동 구성에만 사용 권장
@ConditionalOnMissingBean해당 Bean이 Spring Context에 없을 때 동작자동 구성에만 사용 권장
@ConditionalOnClass특정 클래스가 클래스패스에 존재할 때 설정이 동작특정 라이브러리 의존성 조건 설정
@ConditionalOnMissingClass특정 클래스가 클래스패스에 없을 때 설정이 동작
@ConditionalOnResource특정 자원(e.g., 파일)이 존재할 때 설정이 동작파일 등의 자원 조건 설정
@ConditionalOnProperty특정 프로퍼티가 설정되어 있을 때 동작설정된 프로퍼티 조건 확인
@ConditionalOnJavaJVM 버전에 따라 동작 여부 결정특정 Java 버전 조건
@ConditionalOnWarDeployment전통적인 WAR 배포 방식에서만 동작
@ConditionalOnExpressionSpEL(Spring Expression Language) 표현식의 결과에 따라 동작조건이 복잡할 때 유용

주요 @ConditionalOnXXX 어노테이션 설명

  1. @ConditionalOnWebApplication:
  • 현재 애플리케이션이 웹 애플리케이션인지 확인하고, 웹 환경에서만 빈이 생성되도록 설정합니다.
  • Spring MVC나 Spring WebFlux 등의 웹 환경에서만 동작해야 하는 빈을 설정할 때 유용합니다.
  1. @ConditionalOnBean 및 @ConditionalOnMissingBean:
  • @ConditionalOnBean: 지정한 빈이 존재할 때 동작합니다. 예를 들어, 의존성 빈이 존재할 때만 다른 빈을 생성할 수 있습니다.
  • @ConditionalOnMissingBean: 지정한 빈이 존재하지 않을 때 동작합니다. 보통 자동 구성 클래스에서 기본 빈을 설정할 때 많이 사용됩니다.
  1. @ConditionalOnClass 및 @ConditionalOnMissingClass:
  • @ConditionalOnClass: 클래스패스에 특정 클래스가 존재할 때 동작합니다. 특정 라이브러리 의존성에 따라 빈을 조건부로 생성할 수 있습니다.
  • @ConditionalOnMissingClass: 클래스패스에 특정 클래스가 없을 때 동작합니다. 예를 들어, 필요 없는 의존성이 없을 경우에만 빈을 생성하도록 설정할 수 있습니다.
  1. @ConditionalOnProperty:
  • 특정 프로퍼티의 존재 여부에 따라 설정이 동작합니다. 주로 설정 파일(application.properties 또는 application.yml)에 기반한 조건부 빈 생성을 위해 사용됩니다.
  • 예시: @ConditionalOnProperty(name = "my.property.enabled", havingValue = "true")는 my.property.enabled가 true일 때 빈을 생성합니다.
  1. @ConditionalOnResource:
  • 특정 자원, 예를 들어 파일이나 클래스패스 내 특정 리소스가 존재할 때 설정이 동작하도록 합니다.
  • 주로 외부 파일 또는 설정 파일의 존재에 따라 애플리케이션의 동작을 변경하고자 할 때 사용합니다.
  1. @ConditionalOnExpression:
  • Spring Expression Language(SpEL)을 사용하여 복잡한 조건을 설정할 수 있습니다. 이를 통해 &&, || 등의 논리 연산자를 포함한 조건을 적용할 수 있습니다.
  • 예시: @ConditionalOnExpression("'${my.property}' == 'value'")
  1. @ConditionalOnJava:
  • 현재 JVM 버전에 따라 설정을 적용할 수 있습니다. 예를 들어, Java 11 이상에서만 빈이 활성화되도록 설정할 수 있습니다.
  1. @ConditionalOnWarDeployment:
  • 전통적인 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();
    }
}

위 예제에서:

  • featureService는 feature.enabled 프로퍼티가 true일 때만 생성됩니다.
  • libraryService는 SomeLibrary 클래스가 클래스패스에 존재할 때만 생성됩니다.

결론

  • @Conditional과 @ConditionalOnXXX 어노테이션을 통해 Spring 애플리케이션에서 특정 조건에 맞는 빈을 유연하게 생성하거나 구성할 수 있습니다.

이러한 조건부 어노테이션들은 자동 구성을 더욱 세밀하게 조정하고, 불필요한 빈 생성을 줄이며, 의존성 관리와 리소스 최적화에도 도움을 줍니다.


Q1: @ConditionalOnClass와 @ConditionalOnMissingClass를 효과적으로 활용하여 모듈 간 의존성을 관리하는 방법은 무엇인가요?

@ConditionalOnClass와 @ConditionalOnMissingClass는 특정 모듈이나 라이브러리가 클래스패스에 존재하는지 여부를 확인하여 조건에 맞는 설정을 적용할 수 있습니다.

예를 들어, 여러 기능을 모듈 단위로 나누어 각 모듈이 개별적인 라이브러리를 필요로 한다면, 해당 라이브러리가 클래스패스에 존재할 때만 모듈을 활성화하는 방식으로 의존성을 관리할 수 있습니다.

예시: 예를 들어, AWS 관련 기능을 제공하는 모듈이 aws-java-sdk 라이브러리에 의존할 때, @ConditionalOnClass(name = "com.amazonaws.services.s3.AmazonS3")를 사용하여 aws-java-sdk가 포함된 경우에만 AWS 관련 빈을 활성화할 수 있습니다.

이는 모듈 간 결합도를 낮추고, 불필요한 빈 생성 및 의존성 오류를 방지하는 데 도움이 됩니다.

Q2: @ConditionalOnProperty를 사용할 때 설정 파일에서 관리해야 할 주요 사항들은 무엇인가요?

@ConditionalOnProperty는 주로 application.properties 또는 application.yml 파일의 프로퍼티 설정에 따라 빈을 활성화하거나 비활성화합니다. 이를 효과적으로 관리하려면 다음 사항을 고려해야 합니다.

  • 기본값 설정: 필수적인 설정이 아닐 경우 havingValue나 matchIfMissing 속성을 사용하여 기본값을 설정합니다. 예를 들어, matchIfMissing = true를 설정하면 프로퍼티가 누락되어도 기본적으로 빈이 생성됩니다.

  • 환경 분리: 개발, 테스트, 운영 환경별로 필요한 설정만 활성화하도록 application-{profile}.properties 파일을 활용하여 프로파일 기반 설정을 관리합니다.

  • 명확한 프로퍼티 이름: 프로퍼티 이름은 기능의 목적을 명확히 설명할 수 있도록 합니다. 예를 들어, featureX.enabled와 같은 이름을 사용하면 해당 프로퍼티가 기능 활성화 여부와 관련된 것임을 쉽게 파악할 수 있습니다.

  • 설정 문서화: 프로퍼티 사용에 대한 설명을 코드 주석 또는 문서에 포함하여 다른 개발자들이 각 프로퍼티의 역할과 기본값을 이해할 수 있도록 합니다.

Q3: @ConditionalOnExpression을 사용하여 복잡한 조건을 설정할 때 성능과 유지보수 측면에서 고려해야 할 점은 무엇인가요?

@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 빈이 생성됩니다.

profile
백엔드에서 서버엔지니어가 된 사람

0개의 댓글