ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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 대해서 알아봤다. 좀 더 많은 내용은 문서를 참고하면 되겠다. 사실 문서에 있는지는 모르겠다. 문서를 보고 한게 아니라..

    댓글

Designed by Tistory.