[Spring 3.1 @Enable] 4. @Import와 ImportBeanDefinitionRegistrar

이번에는 옵션에 따라 조금 더 복잡한 빈 조합이 필요한 경우라고 가정하겠습니다. 이런 경우 일일히 모든 경우에 해당하는 @Configuration을 만들기가 힘들기 때문에, 오히려 직접 코딩으로 옵션에 따라 빈을 등록하는 방법이 유용할 수도 있습니다.

이때는 ImportBeanDefinitionRegistrar 구현체를 만들고 이 구현체를 @Import에 설정하면됩니다.

이제는 type 같은 속성이 필요없으며, @Import에는 이 IBDR 구현체를 설정해주면 됩니다.

BeanDefinition을 만드는 API가 그렇게 아름답진 않은데, 빌더 패턴으로 BD를 만드는 API는 없는지 궁금해지네요. 없으면 만들어서 기증해볼까나.

옵션에 따라 등록해야 하는 빈이 매우 복잡하게 달라질 경우에 유용한 방법이 될 수 있겠습니다.

다시 조금 뒤로 돌아가서… 특정 빈 설정을 재사용할 때 그 빈 속성을 확장 가능한 형태로 만들고 싶다면 @Bean 메서드 오버라이딩이나, 템플릿 메서드 패턴을 이용하는 방법을 사용할 수 있었는데, ‘상속’을 이용하기 때문에 치명적인 단점(한가지 @Configuration 밖에 상속하지 못한다, @Overriding으로 주요 로직이 변경될 여지가 생긴다.)이 있었다.

그래서 @Import와 ImportAware, ImportSelector, ImportBeanDefinitionRegistrar를 활용하는 방법으로 빈 설정이나 속성을 확장하는 방법을 살펴봤는데, 이 방법 말고도 Configurer 패턴이라는 방법이 있다.

[Spring 3.1 @Enable] 3. @Import와 ImportSelector

이번에는 새로운 @Configuration을 하나 추가해보죠. 예를 들어, @EnableHello의 type이라는 속성값이 “korean”일때는 HelloKoreanConfig라는 @Configuration을 사용하고, type이 “english”일때는 HelloConfig를 사용하도록 하는거죠.

그리고 ImportSelector 인터페이스 구현체를 만들어서, 특정 애노테이션 속성에 따라 원하는 자바 설정 파일 이름을 리턴해 줍니다. 여기서 ‘왜 Class 타입이 아니라 String 타입의 배열을 리턴할까요?’라고 질문을 했었는데, 아마도 컴파일 시점에 참조할 수 없는 자바 설정도 동적으로 참조할 수 있도록 하려는 것이 아닌가 싶다는 답변을 들을 수 있었습니다.

이제는 @EnableHello 애노테이션에 ImportSelector 구현체에서 사용할 속성을 추가하고, @Import에다 HelloConfig가 아닌 ImportSelector 구현체를 설정합니다.

그럼 이제 AppConfig에 붙인 @EnableHello의 type 속성을 사용해서 전혀 다른 빈 집합이 등록되게 할 수 있습니다.

그런데, 만약에 옵션에 따라 너무도 다양한 빈 조합이 생긴다면, 이렇게 일일히 여러 빈 설정을 만드는 것도 상당히 번거로울 수 있습니다. 오히려 옵션에 따라 코딩으로 빈을 등록하는 방법도 필요할 수 있겠죠.

[Spring 3.1 @Enable] 2. @Import와 ImportAware

이번에는 @Import를 사용해서 빈 설정을 추가하는 방법입니다.

이렇게 @Import 애노테이션을 사용해서 다른 자바 설정을 추가할 수 있습니다. 이렇게하면, 상속을 사용하지 않아도 되지만, 상속했을 때처럼 무언가를 변경할 방법이 보이질 않습니다. 그리고 @Import에 사용할 클래스 이름을 외워야 한다는 문제는 여전히 남게되죠.

일단 @Import를 메타 애노테이션으로 사용하는 @Enable*애노테이션을 만들 수 있습니다.

이렇게 @EnableHello라는 애노테이션을 만들고, @Import로 HelloConfig.java설정을 여기에 추가해뒀습니다. 그럼 이제, AppConfig는 @Import를 직접 사용하는게 아니라, @EnableHello를 이용해서 간접적으로 사용할 수 있게 됩니다.

이제 클래스 이름을 몰라도 되긴하지만, 아직도 확장할 방법은 보이질 않죠. @EnableHello 애노테이션에 속성을 추가하고, 그 애노테이션 정보를 활용해서 빈 정보를 조작할 수 있습니다.

먼저 @EnableHello를 다음과 같이 바꿔보죠.

이렇게 애노테이션에 속성을 추가하면, 이젠 반드시 @EnableHello를 사용할 때 name 값을 줘야 합니다. (물론, default 키워드로 기본값을 설정하면 강제적으로 설정하지 않게 할 수도 있죠.)

그럼 그리고 이제 HelloConfig가 ImportAware라는 인터페이스를 구현하게합니다.

이렇게 ImportAware 인터페이스의 구현 메서드에서 @Import가 붙어있는 곳(여기서는 AppConfig.java)의 애노테이션 정보(@EnableHello)를 바탕으로 빈 속성을 변경하게 했습니다.

이게 끝이아니라, 이제부터 시작입니다.

만약에 지금처럼 단순하게, 빈의 내용만 바꾸는게 아니라, 특정 속성에 따라 등록되어야 하는 빈 자체가 달라진다면 어떻게 해야할까요? 지금은 HelloConfig에 선언한 모든 @Bean이 반드시 빈으로 등록되고 있는데, 특정 옵션에 따라 어떤 빈이 필요하기도 하고, 필요없기도 하다면… ㅎㅎ 문제가 점점 재밌어 집니다.