@Conditional

코딩냥이·2024년 9월 10일

Annotation

목록 보기
19/34

@Conditional

@Conditional 어노테이션은 스프링 프레임워크에서 특정 조건이 충족될 때만 빈을 등록하거나 구성을 적용하도록 하는 기능을 제공합니다.

기능

  • 지정된 조건이 true일 때만 빈을 생성하거나 구성을 적용합니다.
  • 클래스 레벨 또는 메소드 레벨에 적용할 수 있습니다.
  • 사용자 정의 조건을 만들어 복잡한 로직을 구현할 수 있습니다.

사용 방법

import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DatabaseConfig {

    @Bean
    @Conditional(WindowsCondition.class)
    public DataSource windowsDataSource() {
        // Windows 환경용 데이터소스 설정
    }

    @Bean
    @Conditional(LinuxCondition.class)
    public DataSource linuxDataSource() {
        // Linux 환경용 데이터소스 설정
    }
}

주요 특징

  1. 유연한 조건 정의: 사용자 정의 조건을 통해 복잡한 로직을 구현할 수 있습니다.
  2. 세밀한 제어: 빈 등록이나 구성 적용을 매우 세밀하게 제어할 수 있습니다.
  3. 재사용성: 조건 클래스를 재사용하여 일관된 조건 로직을 여러 곳에서 사용할 수 있습니다.
  4. 조합 가능: 여러 조건을 ANDOR 로직으로 조합할 수 있습니다.

조건 클래스 구현

조건 클래스는 Condition 인터페이스를 구현해야 합니다:

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").toLowerCase().contains("windows");
    }
}

스프링 부트의 내장 Conditional 어노테이션

스프링 부트는 자주 사용되는 조건들을 위한 내장 @Conditional 어노테이션을 제공합니다:

  1. @ConditionalOnClass: 특정 클래스가 클래스패스에 있을 때

    @Bean
    @ConditionalOnClass(name = "org.springframework.data.redis.core.RedisTemplate")
    public RedisTemplate redisTemplate() {
        // Redis 관련 빈 설정
    }
  2. @ConditionalOnMissingBean: 특정 빈이 없을 때

    @Bean
    @ConditionalOnMissingBean
    public DataSource defaultDataSource() {
        // 기본 DataSource 빈 설정
    }
  3. @ConditionalOnProperty: 특정 프로퍼티가 지정된 값을 가질 때

    @Bean
    @ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
    public FeatureService featureService() {
        // 특정 기능 활성화 시 사용되는 서비스
    }
  4. @ConditionalOnExpression: SpEL 표현식이 true일 때

    @Bean
    @ConditionalOnExpression("${app.scheduling.enabled:true} and '${app.mode}' == 'FULL'")
    public TaskScheduler taskScheduler() {
        // 특정 조건에서 사용되는 TaskScheduler
    }

복합 조건 사용

여러 조건을 조합하여 사용할 수 있습니다:

@Configuration
@Conditional({LinuxCondition.class, Java8Condition.class})
public class LinuxJava8Config {
    // Linux 환경이면서 Java 8일 때 적용되는 설정
}

@Profile vs @Conditional

@Profile@Conditional의 특별한 케이스입니다. @Conditional을 사용하면 @Profile보다 더 세밀하고 복잡한 조건을 지정할 수 있습니다:

@Configuration
@Conditional(ProductionCondition.class)
public class ProductionConfig {
    // ProductionCondition 클래스에 정의된 복잡한 조건이 충족될 때 적용되는 설정
}

테스트에서의 사용

테스트 환경에서 특정 조건에 따라 테스트를 실행하거나 건너뛰기 위해 @Conditional을 사용할 수 있습니다:

@SpringBootTest
class MyServiceTest {

    @Test
    @Conditional(DatabaseAvailableCondition.class)
    void testWithDatabase() {
        // 데이터베이스가 사용 가능할 때만 실행되는 테스트
    }
}

주의사항

  1. 복잡성 관리: 너무 많은 조건부 로직은 애플리케이션을 복잡하게 만들 수 있습니다.
  2. 성능 고려: 복잡한 조건 검사는 애플리케이션 시작 시간에 영향을 줄 수 있습니다.
  3. 디버깅 어려움: 조건부 로직이 많으면 빈이 예상대로 등록되지 않았을 때 원인을 찾기 어려울 수 있습니다.

베스트 프랙티스

  1. 명확한 조건 정의: 조건 클래스의 이름과 로직을 명확하게 정의하세요.
  2. 재사용성 고려: 공통으로 사용되는 조건은 별도의 클래스로 추출하여 재사용하세요.
  3. 문서화: 복잡한 조건 로직은 주석이나 문서로 설명을 추가하세요.
  4. 테스트 커버리지: 다양한 조건에 대한 테스트 케이스를 작성하세요.
  5. 단순화: 가능한 한 조건 로직을 단순하게 유지하세요.

결론

@Conditional 어노테이션은 스프링 애플리케이션의 유연성을 크게 향상시키는 강력한 도구입니다. 이를 통해 환경, 설정, 클래스 존재 여부 등 다양한 조건에 따라 애플리케이션의 동작을 세밀하게 제어할 수 있습니다. 그러나 과도한 사용은 애플리케이션을 복잡하게 만들 수 있으므로, 적절한 균형을 유지하는 것이 중요합니다.

연관 포스팅

@Profile
@Configuration
@Bean
@ConfigurationProperties
@EnableAutoConfiguration

profile
HelloMeow~!

0개의 댓글