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