본문 바로가기
Homo Faber/Idioms

Spring에서 annotation 태그 사용하기 (2)

by javauser 2008. 2. 20.
Qualifier를 사용하는 annotation 기반 자동엮음(autowiring) 세부 조정

타입에 의한 자동엮음(autowiring)은 여러개의 빈이 엮여질 수 있기 때문에 선택 과정에 대해서 좀 더 제어를 할 필요가 종종 있다. 이를 하기 위한 한가지 방법은 Spring의 @Qualifier annotation을 사용하는 것이다. 가장 단순한 경우, annotation 내의 빈 이름을 써서 byName 자동엮음을 할 수 있다.
public class MovieRecommender {
   @Autowired
   @Qualifier("mainCatalog")
   private MovieCatalog movieCatalog;
   // ...
}

@Qualifier annotation은 또한 개개의 생성자 인자나 메소드 파라미터에 지정이 가능하다.
public class MovieRecommender {
   private MovieCatalog movieCatalog;
   private CustomerPreferenceDao customerPreferenceDao;
   @Autowired
   public void prepare(@Qualifier("mainCatalog") MovieCatalog movieCatalog,
         CustomerPreferenceDao customerPreferenceDao) {
      this.movieCatalog = movieCatalog;
      this.customerPreferenceDao = customerPreferenceDao;
   }
   // ...
}

또한 사용자에 맞는 qualifier annotation을 만들 수도 있다. 단순하게 annotation을 정의하고 정의 내에 @Qualifier annotation을 쓰면 된다.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
   String value();
}
그 다음에 자동엮음을 하려는 필드와 파라미터에 만들어진 qualifier를 적용할 수 있다.
public class MovieRecommender {
   @Autowired
   @Genre("Action")
   private MovieCatalog actionCatalog;
   private MovieCatalog comedyCatalog;
   @Autowired
   public void setComedyCatalog(@Genre("Comedy")
         MovieCatalog comedyCatalog) {
      this.comedyCatalog = comedyCatalog;
   }
   // ...
}
다음 단계는 자동엮여질 후보 빈 정의에 해당 정보를 추가하는 것이다. <bean/> 태그의 하위 요소로 <qualifier/> 태그를 추가하고 나서 만들어진 qualifier annotation과 일치하는 'type'과 'value'를 지정한다. type은 annotation의 패키지를 포함한 전체 클래스명과 일치하거나, 이름이 충돌날 염려가 없는 경우에는 '짧은' 클래스명을 사용할 수 있다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-2.5.xsd">
   <context:annotation-config/>
   <bean class="example.SimpleMovieCatalog">
      <qualifier type="Genre" value="Action"/>
      <!-- inject any dependencies required by this bean -->
   </bean>
   <bean class="example.SimpleMovieCatalog">
      <qualifier type="example.Genre" value="Comedy"/>
      <!-- inject any dependencies required by this bean -->
   </bean>
   <bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>

어떤 경우에는 value 없이 annotation을 사용하는 것으로 충분한 경우가 있다. 이는 annotation이 좀 더 일반적인 목적으로 사용되고 몇몇 다른 type의 의존성으로 적용될 때 유용하다. 예를 들어, 어떠한 인터넷 연결이 안되었을 때에 검색될 수 있는 offline 카탈로그를 제공할 수도 있다. 먼저 단순한 annotation을 다음과 같이 정의한다.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
그 다음에 자동엮여질 필드나 속성에 annotation을 추가한다.
public class MovieRecommender {
   @Autowired
   @Offline
   private MovieCatalog offlineCatalog;
   // ...
}
이제 빈 정의는 qualifier 'type' 만 필요하다.
<bean class="example.SimpleMovieCatalog">
   <qualifier type="Offline"/>
   <!-- inject any dependencies required by this bean -->
</bean>

추가로 혹은 단순한 'value' 속성 대신에 이름이 지정된 속성을 받아들이는 qualifier annotation을 정의할 수도 있다. 만일 여러개의 속성 값들이 자동엮여질 필드나 파라미터에 지정된다면 빈 정의는 자동엮음 대상이라고 생각되는 속성 값 모두와 일치해야 한다. 예를 들어, 다음과 같은 annotation 정의를 생각할 수 있다.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
   String genre();
   Format format();
}
이 경우 Format은 다음과 같은 enum 이다.
public enum Format {
   VHS, DVD, BLURAY;
}
마지막으로 빈 정의는 qualifier 값들에 대한 일치하는 것을 포함해야 한다. 이 예제에서는 또한 bean의 meta 속성이 <qualifier/> 하위 요소 대신에 사용될 수 있음을 보여준다. 가능하다면, <qualifier/> 와 그 속성들이 우선시되지만, 자동엮음 메커니즘은 qualifier 가 존재하지 않는다면 <meta/> 태그 내에서 제공되는 값을 대신 사용하게 된다. (마지막 2개의 빈 정의 참조)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-2.5.xsd">
   <context:annotation-config/>
   <bean class="example.SimpleMovieCatalog">
      <qualifier type="MovieQualifier">
         <attribute name="format" value="VHS"/>
         <attribute name="genre" value="Action"/>
      </qualifier>
      <!-- inject any dependencies required by this bean -->
   </bean>
   <bean class="example.SimpleMovieCatalog">
      <qualifier type="MovieQualifier">
         <attribute name="format" value="VHS"/>
         <attribute name="genre" value="Comedy"/>
      </qualifier>
      <!-- inject any dependencies required by this bean -->
   <bean>
   <bean class="example.SimpleMovieCatalog">
      <meta key="format" value="DVD"/>
      <meta key="genre" value="Action"/>
      <!-- inject any dependencies required by this bean -->
    <bean>
    <bean class="example.SimpleMovieCatalog">
      <meta key="format" value="BLURAY"/>
      <meta key="genre" value="Comedy"/>
      <!-- inject any dependencies required by this bean -->
    <bean>
</beans>
반응형