카테고리 없음

Spring boot NestedCondition

머룽 2023. 4. 23. 14:05
오늘 알아볼 내용은 Spring boot 에서 지원해주는 NestedCondition 에서 대해서 알아보도록 하자. Spring boot 에서는 많은 Condition을 지원해 주고 있지만 그중에서 NestedCondition 에 대해서 알아볼 것이다. 사실 Spring boot **Condition 들의 최상위 인터페이스는 Spring boot 에서 지원해주는 인터페이스가 아닌 Spring 에서 지원해주고 있는 인터페이스이다. 그 중 대표적인 Spring의 condition은 우리가 많이 사용하고 있는 ProfileCondition 이니 참고하면 되겠다. 나머지 Spring boot 의 Condition 들은 여기나 다른 블로그 혹은 문서를 참고하면 되겠다. NestedCondition는 대표적으로 3의 클래스를 갖고 있는데 그 3개 모두 AbstractNestedCondition 클래스를 구현하고 있다. 가장 기본의 되는 클래스이다. 한개씩 살펴보도록 하자.

AnyNestedCondition

AnyNestedCondition 는 어느 한 조건만 만족하면 된다. 예를들어 어떤 빈들이 존재한다거나, 존재 하지 않다거나 등 여러 조건을 만들수 있는데 그 중 하나의 조건만 만족해도 동작한다. 또한 @ConditionalOnBean이 or 조건 에서 and 조건으로 변경되면서 or 조건을 사용할 경우 이 클래스를 이용하면 된다. 일단 한번 코드를 작성해보자.
public class Bar {
}

public class Foo {
}

public class FooService {
}
이런 샘플 코드가 있다고 가정하자. Foo와 Bar는 조건에 넣을 클래스이고 FooService 경우에는 해당 조건이 만족할 때 등록 되는 빈으로 사용할 예정이다.
@Configuration
@Conditional(AnyCondition.class)
public class AnyConfig {

  @Bean
  FooService fooService() {
    return new FooService();
  }

  static class AnyCondition extends AnyNestedCondition {

    public AnyCondition() {
      super(ConfigurationPhase.REGISTER_BEAN);
    }

    @ConditionalOnBean(Foo.class)
    static class FooCondition {

    }

    @ConditionalOnBean(Bar.class)
    static class BarCondition {

    }
  }
}

위와 같이 AnyNestedCondition를 상속받아서 구현?.. 설정하면 된다. ConfigurationPhase 타입의 생성자는 필수이기에 위와 같이 작성해준다. 그리고 나서 해당 조건을 작성하면 된다.
@ConditionalOnBean(Foo.class)
static class FooCondition {

}
이 뜻은 Foo라는 빈이 존재할 경우 해당 설정을 적용하라는 의미이다. 그 아래 Bar 클래스도 동일하다. 위와 같이 작성할 경우엔 FooService 가 빈으로 등록 되지 않는다. 왜냐하면 Foo, Bar 모두 빈으로 등록 되어 있지 않기 때문이다. 만약 FooService를 빈으로 등록 되게 하고 싶다면 아래와 같이 작성해야 한다.
@Component
public class Foo {
}

or 

@Component
public class Bar {
}

Foo, Bar 둘중에 하나만 빈으로 등록 시키면 된다. 어렵지 않다.

NoneNestedConditions

NoneNestedConditions 는 클래스명의 의미와 동일하게 모두 만족하지 않으면 동작한다. 하나라도 만족하면 동작하지 않는다.
@Configuration
@Conditional(NoneCondition.class)
public class NoneConfig {

  @Bean
  FooService fooService() {
    return new FooService();
  }

  static class NoneCondition extends NoneNestedConditions {

    public NoneCondition() {
      super(ConfigurationPhase.REGISTER_BEAN);
    }

    @ConditionalOnBean(Foo.class)
    static class FooCondition {

    }
    @ConditionalOnBean(Bar.class)
    static class BarCondition {

    }
  }
}
AnyNestedCondition와 마찬가지로 NoneNestedConditions를 구현하면 된다. 구현은 AnyNestedCondition와 동일하다.

AllNestedConditions

AllNestedConditions은 해당 조건을 모두 만족해야 한다. 이것 역시 하나라도 만족하지 않으면 동작하지 않는다.
@Configuration
@Conditional(AllCondition.class)
public class AllConfig {

  @Bean
  FooService fooService() {
    return new FooService();
  }

  static class AllCondition extends AllNestedConditions {

    public AllCondition() {
      super(ConfigurationPhase.REGISTER_BEAN);
    }

    @ConditionalOnBean(Foo.class)
    static class FooCondition {

    }

    @ConditionalOnBean(Bar.class)
    static class BarCondition {

    }
  }
}
AllNestedConditions을 구현하면 된다. 쉽다. 딱히 어려운 부분은 없는 것 같다. 여기에서는 ConditionalOnBean만 사용했는데 꼭 그럴필요는 없다. @ConditionalOnMissingBean, @ConditionalOnClass, @ConditionalOnMissingClass@ConditionalOn** 다 동작할 것이다. (하지만 다 해보진 않았다.) @ConditionalOnProperty 하나만 예제로 만들어 봤다.
static class AnyCondition extends AnyNestedCondition {

  public AnyCondition() {
    super(ConfigurationPhase.REGISTER_BEAN);
  }

  @ConditionalOnBean(Foo.class)
  static class FooCondition {

  }

  @ConditionalOnProperty(prefix = "foo", name = "name")
  static class BarCondition {

  }
}
이와 같이 작성할 경우 foo.name의 키를 갖고 있는 프로퍼티를 작성해주면 된다.
foo.name=wonwoo
그럼 해당 condition을 만족하여 동작한다. 여기서 ConfigurationPhase 라는 enum이 존재하는데 두가지 타입을 제공해준다. PARSE_CONFIGURATION, REGISTER_BEAN 이다. 아주 자세히는 모르겠지만 해당 문서를 보면 이렇다. PARSE_CONFIGURATION 경우에는 @Configuration 어노테이션을 파싱할떄 조건을 평가한다. (ConfigurationClassParser) REGISTER_BEAN 경우에는 빈을 추가 할때 조건을 평가한다. (ConfigurationClassBeanDefinitionReader) 음.. 글쎄다 사실 시점이 문제인 것 같다. 언제 조건을 평가하는지를 설정하는 듯하다. 대부분의 경우에는 빈을 추가할 때 시점으로 사용하면 문제 없을 듯 하다. 언제는 예외는 있기에.. PARSE_CONFIGURATION 사용하는 클래스들을 살펴보면 좀 더 알지 않을까 생각된다. 이상으로 오늘은 Spring boot의 NestedCondition 대해서 알아봤다. 좀 더 많은 내용은 문서를 참고하면 되겠다. 사실 문서에 있는지는 모르겠다. 문서를 보고 한게 아니라..