Loading...
Spring Framework Reference Documentation 7.0.2의 Fine-tuning Annotation-based Autowiring with Qualifiers의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
@Primary 및 @Fallback는 하나의 primary(또는 non-fallback) candidate를 결정할 수 있을 때
여러 instance에 대해 type 기반 autowiring을 사용하는 효과적인 방법입니다.
선택 과정에 대해 더 많은 제어가 필요할 때는 Spring의 @Qualifier
어노테이션을 사용할 수 있습니다. qualifier 값들을 특정 argument와 연관시켜서 type 일치
집합을 좁힘으로써 각 argument에 대해 특정 빈이 선택되도록 할 수 있습니다.
가장 단순한 경우에는 다음 예제와 같이 일반적인 설명용 값을 사용할 수 있습니다:
1public class MovieRecommender { 2 3 @Autowired 4 @Qualifier("main") 5 private MovieCatalog movieCatalog; 6 7 // ... 8}
1class MovieRecommender { 2 3 @Autowired 4 @Qualifier("main") 5 private lateinit var movieCatalog: MovieCatalog 6 7 // ... 8}
또한 다음 예제와 같이 개별 constructor argument나
메서드 parameter에 @Qualifier 어노테이션을 지정할 수도 있습니다:
1public class MovieRecommender { 2 3 private final MovieCatalog movieCatalog; 4 5 private final CustomerPreferenceDao customerPreferenceDao; 6 7 @Autowired 8 public void prepare(@Qualifier("main") MovieCatalog movieCatalog, 9 CustomerPreferenceDao customerPreferenceDao) { 10 this.movieCatalog = movieCatalog; 11 this.customerPreferenceDao = customerPreferenceDao; 12 } 13 14 // ... 15}
1class MovieRecommender { 2 3 private lateinit var movieCatalog: MovieCatalog 4 5 private lateinit var customerPreferenceDao: CustomerPreferenceDao 6 7 @Autowired 8 fun prepare(@Qualifier("main") movieCatalog: MovieCatalog, 9 customerPreferenceDao: CustomerPreferenceDao) { 10 this.movieCatalog = movieCatalog 11 this.customerPreferenceDao = customerPreferenceDao 12 } 13 14 // ... 15}
다음 예제는 이에 상응하는 빈 definition을 보여줍니다.
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <context:annotation-config/> 11 12 <bean class="example.SimpleMovieCatalog"> 13 <qualifier value="main"/> (1) 14 15 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 16 </bean> 17 18 <bean class="example.SimpleMovieCatalog"> 19 <qualifier value="action"/> (2) 20 21 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 22 </bean> 23 24 <bean id="movieRecommender" class="example.MovieRecommender"/> 25 26</beans>
| 1 | main qualifier 값을 가진 빈은 동일한 값으로 qualifier가 지정된<br>constructor argument와 연결됩니다. |
| 2 | action qualifier 값을 가진 빈은 동일한 값으로 qualifier가 지정된<br>constructor argument와 연결됩니다. |
fallback match의 경우, 빈 name은 기본 qualifier 값으로 간주됩니다. 따라서
nested qualifier element 대신 id가 main인 빈을 정의할 수 있으며,
동일한 matching 결과를 얻게 됩니다.
그러나 이 관례를 사용하여 이름으로
특정 빈을 참조할 수는 있지만, @Autowired는 근본적으로 선택적 semantic qualifier를
동반한 type-driven injection에 관한 것입니다. 이는 qualifier 값들이 빈 name fallback이
있더라도 항상 type match 집합 내에서 범위를 좁히는 의미를 가진다는 것을 뜻합니다.
이들은 고유한 빈 id에 대한 참조를 의미적으로 표현하지는 않습니다. 좋은 qualifier 값의
예로는 main, EMEA, persistent 등이 있으며, 이는 앞선 예제와 같은
anonymous 빈 definition의 경우 자동 생성될 수 있는 빈 id와는 독립적인
특정 컴포넌트의 특성을 표현합니다.
Qualifier는 앞에서 논의한 것처럼 typed collection에도 적용됩니다. 예를 들어
Set<MovieCatalog>에 적용할 수 있습니다. 이 경우 선언된 qualifier에 따라
모든 일치하는 빈이 컬렉션으로 주입됩니다.
이는 qualifier가
고유할 필요는 없다는 것을 의미합니다. 오히려 qualifier는 filtering criteria를 구성합니다.
예를 들어 동일한 qualifier 값 “action”을 가진 여러 MovieCatalog 빈을 정의할 수 있으며,
이들은 모두 @Qualifier("action")이 붙은 Set<MovieCatalog>에
주입됩니다.
Type-matching candidate 내에서 target 빈 name에 대해 qualifier 값을 선택하도록<br>하는 것은 injection 지점에
@Qualifier어노테이션이 필요하지 않습니다.<br>다른 resolution indicator(qualifier나 primary marker 등)가 없고,<br>dependency가 non-unique한 상황에서는 Spring이 injection 지점 이름<br>(즉, field name 또는 parameter name)을 target 빈 name과 비교하여,<br>(빈 name 또는 연관된 alias 중) 동일한 이름의 candidate가 있다면 이를 선택합니다.<br>6.1 버전부터는 이를 위해-parametersJava compiler flag가 필요합니다.<br>6.2부터는 parameter name이 빈 name과 일치하고 type, qualifier, primary 조건이<br>match를 override하지 않는 경우, 컨테이너가 전체 type matching algorithm을<br>우회하고 빈 name match에 대해 빠른 shortcut resolution을 적용합니다.<br>따라서 parameter name이 target 빈 name과 일치하도록 하는 것이 바람직합니다.
이름 기반 injection의 대안으로는 JSR-250 @Resource 어노테이션을 고려할 수 있으며,
이는 matching 과정에서 선언된 type은 무관하게 고유한 이름으로 특정 target 컴포넌트를
식별하도록 semantic이 정의되어 있습니다. @Autowired는 상당히 다른 semantic을
가집니다.
Type으로 candidate 빈을 선택한 후, 지정된 String
qualifier 값은 그러한 type-selected candidate 내에서만 고려됩니다(예를 들어,
account qualifier를 동일한 qualifier label로 표시된 빈과 match시키는 경우).
자체가 컬렉션, Map, array type으로 정의된 빈에 대해서는,
고유한 이름으로 특정 컬렉션 또는 array 빈을 참조하는 @Resource가
좋은 해결책입니다. 그렇긴 하지만 element type 정보가 @Bean return type signature나
컬렉션 inheritance hierarchy에 보존되어 있는 한, Spring의
@Autowired type matching algorithm을 통해 컬렉션, Map, array type도
match시킬 수 있습니다.
이 경우, 앞 단락에서 설명한 것처럼 qualifier 값을 사용하여 동일 type의 컬렉션 중에서 선택할 수 있습니다.
@Autowired는 injection을 위한 self reference(즉, 현재 주입 중인 빈으로의
역참조)도 고려합니다. 자세한 내용은
Self Injection
을 참조하십시오.
@Autowired는 field, constructor, multi-argument 메서드에 적용되며,
parameter 수준의 qualifier 어노테이션을 통해 범위를 좁힐 수 있습니다. 반대로
@Resource는 single argument를 가진 field 및 빈 property setter 메서드에만
지원됩니다.
결과적으로 injection target이 constructor나 multi-argument 메서드인 경우에는 qualifier를 사용하는 것이 좋습니다.
사용자 정의 qualifier 어노테이션을 만들 수도 있습니다. 이를 위해 어노테이션을 정의하고
다음 예제와 같이 정의 내에 @Qualifier 어노테이션을 제공하면 됩니다:
1@Target({ElementType.FIELD, ElementType.PARAMETER}) 2@Retention(RetentionPolicy.RUNTIME) 3@Qualifier 4public @interface Genre { 5 6 String value(); 7}
1@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) 2@Retention(AnnotationRetention.RUNTIME) 3@Qualifier 4annotation class Genre(val value: String)
그런 다음 다음 예제와 같이 autowired field 및 parameter에 custom qualifier를 제공할 수 있습니다:
1public class MovieRecommender { 2 3 @Autowired 4 @Genre("Action") 5 private MovieCatalog actionCatalog; 6 7 private MovieCatalog comedyCatalog; 8 9 @Autowired 10 public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) { 11 this.comedyCatalog = comedyCatalog; 12 } 13 14 // ... 15}
1class MovieRecommender { 2 3 @Autowired 4 @Genre("Action") 5 private lateinit var actionCatalog: MovieCatalog 6 7 private lateinit var comedyCatalog: MovieCatalog 8 9 @Autowired 10 fun setComedyCatalog(@Genre("Comedy") comedyCatalog: MovieCatalog) { 11 this.comedyCatalog = comedyCatalog 12 } 13 14 // ... 15}
다음으로 candidate 빈 definition에 대한 정보를 제공할 수 있습니다. <bean/> tag의
sub-element로 <qualifier/> tag를 추가한 다음, custom qualifier 어노테이션과
일치하도록 type 및 value를 지정할 수 있습니다.
type은 어노테이션의 fully-qualified class name과 match됩니다. 또는 이름 충돌 위험이 없다면 편의상 short class name을 사용할 수 있습니다. 다음 예제는 두 접근 방식을 모두 보여줍니다:
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <context:annotation-config/> 11 12 <bean class="example.SimpleMovieCatalog"> 13 <qualifier type="Genre" value="Action"/> 14 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 15 </bean> 16 17 <bean class="example.SimpleMovieCatalog"> 18 <qualifier type="example.Genre" value="Comedy"/> 19 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 20 </bean> 21 22 <bean id="movieRecommender" class="example.MovieRecommender"/> 23 24</beans>
Classpath Scanning and Managed Components에서 qualifier 메타데이터를 XML로 제공하는 어노테이션 기반 대안을 확인할 수 있습니다. 특히 Providing Qualifier Metadata with Annotations를 참조하십시오.
일부 경우에는 값이 없는 어노테이션을 사용하는 것만으로도 충분할 수 있습니다. 이는 어노테이션이 보다 일반적인 목적을 가지며 여러 종류의 의존성에 걸쳐 적용될 수 있을 때 유용합니다.
예를 들어 Internet 연결이 가능하지 않을 때 검색할 수 있는 offline catalog를 제공할 수 있습니다. 먼저 다음 예제와 같이 간단한 어노테이션을 정의합니다:
1@Target({ElementType.FIELD, ElementType.PARAMETER}) 2@Retention(RetentionPolicy.RUNTIME) 3@Qualifier 4public @interface Offline { 5}
1@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) 2@Retention(AnnotationRetention.RUNTIME) 3@Qualifier 4annotation class Offline
그런 다음 다음 예제와 같이 autowiring 대상 field 또는 property에 어노테이션을 추가합니다:
1public class MovieRecommender { 2 3 @Autowired 4 @Offline (1) 5 private MovieCatalog offlineCatalog; 6 7 // ... 8}
| 1 | 이 line은 @Offline 어노테이션을 추가합니다. |
1class MovieRecommender { 2 3 @Autowired 4 @Offline (1) 5 private lateinit var offlineCatalog: MovieCatalog 6 7 // ... 8}
| 1 | 이 line은 @Offline 어노테이션을 추가합니다. |
이제 빈 definition에는 qualifier type만 필요하며, 다음 예제와 같습니다:
1<bean class="example.SimpleMovieCatalog"> 2 <qualifier type="Offline"/> (1) 3 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 4</bean>
| 1 | 이 element는 qualifier를 지정합니다. |
또한 simple value attribute 외에 named attribute를 허용하는
custom qualifier 어노테이션을 정의할 수도 있습니다. 그런 다음 autowiring 대상
field 또는 parameter에 대해 여러 attribute 값이 지정되면,
빈 definition은 autowire candidate로 간주되기 위해 그러한 모든 attribute 값을
match해야 합니다.
예로서 다음 어노테이션 definition을 고려해 보십시오:
1@Target({ElementType.FIELD, ElementType.PARAMETER}) 2@Retention(RetentionPolicy.RUNTIME) 3@Qualifier 4public @interface MovieQualifier { 5 6 String genre(); 7 8 Format format(); 9}
1@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER) 2@Retention(AnnotationRetention.RUNTIME) 3@Qualifier 4annotation class MovieQualifier(val genre: String, val format: Format)
이 경우 Format은 다음과 같이 정의된 enum입니다:
1public enum Format { 2 VHS, DVD, BLURAY 3}
1enum class Format { 2 VHS, DVD, BLURAY 3}
Autowiring 대상 field는 custom qualifier로 어노테이션되어 있으며,
다음 예제와 같이 genre 및 format 두 attribute에 대한 값을 포함합니다:
1public class MovieRecommender { 2 3 @Autowired 4 @MovieQualifier(format=Format.VHS, genre="Action") 5 private MovieCatalog actionVhsCatalog; 6 7 @Autowired 8 @MovieQualifier(format=Format.VHS, genre="Comedy") 9 private MovieCatalog comedyVhsCatalog; 10 11 @Autowired 12 @MovieQualifier(format=Format.DVD, genre="Action") 13 private MovieCatalog actionDvdCatalog; 14 15 @Autowired 16 @MovieQualifier(format=Format.BLURAY, genre="Comedy") 17 private MovieCatalog comedyBluRayCatalog; 18 19 // ... 20}
1class MovieRecommender { 2 3 @Autowired 4 @MovieQualifier(format = Format.VHS, genre = "Action") 5 private lateinit var actionVhsCatalog: MovieCatalog 6 7 @Autowired 8 @MovieQualifier(format = Format.VHS, genre = "Comedy") 9 private lateinit var comedyVhsCatalog: MovieCatalog 10 11 @Autowired 12 @MovieQualifier(format = Format.DVD, genre = "Action") 13 private lateinit var actionDvdCatalog: MovieCatalog 14 15 @Autowired 16 @MovieQualifier(format = Format.BLURAY, genre = "Comedy") 17 private lateinit var comedyBluRayCatalog: MovieCatalog 18 19 // ... 20}
마지막으로 빈 definition에는 일치하는 qualifier 값이 포함되어야 합니다. 이 예제는
<qualifier/> element 대신 빈 meta attribute를 사용할 수 있다는 것도
보여줍니다.
사용 가능한 경우 <qualifier/> element와 그 attribute가
우선권을 가지지만, autowiring mechanism은 다음 예제의 마지막 두 빈 definition에서처럼
qualifier가 존재하지 않으면 <meta/> tag 내에서 제공된 값으로
fallback합니다:
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <context:annotation-config/> 11 12 <bean class="example.SimpleMovieCatalog"> 13 <qualifier type="MovieQualifier"> 14 <attribute key="format" value="VHS"/> 15 <attribute key="genre" value="Action"/> 16 </qualifier> 17 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 18 </bean> 19 20 <bean class="example.SimpleMovieCatalog"> 21 <qualifier type="MovieQualifier"> 22 <attribute key="format" value="VHS"/> 23 <attribute key="genre" value="Comedy"/> 24 </qualifier> 25 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 26 </bean> 27 28 <bean class="example.SimpleMovieCatalog"> 29 <meta key="format" value="DVD"/> 30 <meta key="genre" value="Action"/> 31 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 32 </bean> 33 34 <bean class="example.SimpleMovieCatalog"> 35 <meta key="format" value="BLURAY"/> 36 <meta key="genre" value="Comedy"/> 37 <!-- 이 빈에 필요한 모든 의존성을 주입합니다 --> 38 </bean> 39 40</beans>
Fine-tuning Annotation-based Autowiring with @Primary or @Fallback
Using Generics as Autowiring Qualifiers