https://sundaland.tistory.com/475
▶ Fine-tuning Annotation-based Autowiring with Qualifiers
@Primary는 여러 인스턴스가 있을 때 특정 후보를 자동 주입하는데 유용하다. 하지만 선택 과정을 더 세밀하게 제어해야 할 때는 스프링은 @Qualifier 어노테이션을 사용할 수 있다. @Qualifier를 사용하면 특정 아규먼트에 qualifier을 연결하여 타입 일치의 범위를 좁히고, 특정 빈이 각 아규먼트에 선택되도록 할 수 있다. 가장 단순한 경우는 아래 예시에ㅘ 같은 간단한 설명적 값일 수 있다.
public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}
또한 개별 생성자 아규먼트나 메서드 파라미터에 @Qualifier 어노테이션을 지정할 수도 있다.
▼ 메서드 파라미터에 @Qualifier 어노테이션을 지정하는 방법
public class MovieRecommender {
private final MovieCatalog movieCatalog;
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
▼ 위의 예시에 해당하는 빈 정의
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier value="action"/>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
main qualifier 값을 가진 빈은 동일한 qualifier 값으로 지정된 생성자 아규먼트와 연결된다. action qualifier 값을 가진 빈도 동일하게 처리된다. 기본적으로 빈 이름은 qualifier 값으로 간주될 수 있다. 따라서 main 이라는 ID로 빈을 정의하면 같은 일치 결과를 얻을 수 있다. 그러나 이름을 통해 특정 빈을 참조할 때 @Autowired는 타입 기반 주입에 대한 것으로, qualifier 값은 타입 일치 후바 내에서만 의미가 있다. 좋은 qualifier 값은 main, EMEA, persitent와 같은 값으로, 이는 빈 ID와 독립적인 특정 구성 요소의 특성을 나타낸다.
▷ @Qualifier와 빈 이름의 기본 개념
스프링에서 자동 주입 (autowiring)은 주로 타입에 기반하여 동작한다. 즉, 타입 일치에 따라 적절한 빈이 주입된다. 그러나 같은 타입의 빈이 여러 개 존재할 때, 어떤 빈을 주입할지 결정하는데 더 세밀한 제어가 필요하다. 이때 사용하는 것이 @Qualifier 어노테이션이다.
- @Qualifier: 특정한 자격 값 (qualifier value)을 사영하여 주입할 빈을 더 구체적으로 지정할 수 있다. 타입 일치 후보 내에서 @Qualifier를 사용해 범위를 좁힌다.
- 빈 이름: 스프링에서 빈의 ID는 기본적으로 자격 값으로 간주될 수 있다. 즉, 빈 이름과 동일한 자격 값이 주입 지점에서 사용되면 해당 빈이 선택될 수 있다.
▷ 빈 이름과 @Qualifier의 관계
기본적으로 빈 이름은 자격 값으로 간주될 수 있다.
- 빈 이름이 main인 빈만 있을 때, @Qualifier("main")을 사용하면 동일한 빈이 주입될 수 있다.
- 이때, @Qualifier를 사용하는 것은 주입할 빈을 더 명확하게 지정하는 방식으로 작동한다. 하지만, 빈 이름만으로도 동일한 효과를 얻을 수 있다.
▷ 빈 ID와 @Qualifier의 차이점
- 빈 ID는 주로 빈을 식별하는 역할을 하며, XML이나 자바 구성에서 빈을 참조하는데 사용된다.
- @Qualifier는 타입 일치 후보 내에서 주입할 빈을 선택하는데 사용된다. 즉, 여러개의 빈이 동일한 타입을 가지고 있을 때, 특정 특성을 가진 빈을 주입하는데 유용하다.
▷ 실용적인 예시
아래와 같은 빈 정의가 있다가 가정한다.
@Bean
@Qualifier("main")
public MovieCatalog mainMovieCatalog() {
return new MainMovieCatalog();
}
@Bean
@Qualifier("action")
public MovieCatalog actionMovieCatalog() {
return new ActionMovieCatalog();
}
그리고 다음과 같이 MovieRecommender 클래스에서 @Autowired와 @Qualifier를 사용하여 빈을 주입한다고 가정한다.
public class MovieRecommender {
private final MovieCatalog mainCatalog;
private final MovieCatalog actionCatalog;
@Autowired
public MovieRecommender(@Qualifier("main") MovieCatalog mainCatalog,
@Qualifier("action") MovieCatalog actionCatalog) {
this.mainCatalog = mainCatalog;
this.actionCatalog = actionCatalog;
}
// ...
}
이 경우, MovieRecommender는 @Qualifier("main")로 지정된 mainMovieCatalog 빈과 @Qualifier("action")로 지정된 actionMovieCatalog 빈을 주입받게 된다.
▷ 빈 이름을 사용한 주입
@Qualifier를 사용하지 않고도 동일한 빈을 주입받을 수 있다. 빈 이름을 자격 값으로 간주하여 동일한 빈을 선택할 수 있기 때문이다.
@Bean(name = "main")
public MovieCatalog mainMovieCatalog() {
return new MainMovieCatalog();
}
@Bean(name = "action")
public MovieCatalog actionMovieCatalog() {
return new ActionMovieCatalog();
}
빈 이름을 main과 action으로 지정하면, @Qualifier("main") 없이도 빈을 주입받을 수 있다.
public class MovieRecommender {
private final MovieCatalog mainCatalog;
private final MovieCatalog actionCatalog;
@Autowired
public MovieRecommender(MovieCatalog main, MovieCatalog action) {
this.mainCatalog = main;
this.actionCatalog = action;
}
// ...
}
이 경우, 필드 이름이나 파라미터 이름이 빈 이름과 일치하기 때문에 스프링은 main과 action이라는 이름을 가진 빈을 자동으로 주입한다.
▷ 좋은 @Qualifier 값의 예시
좋은 @Qualifier 값은 빈 ID와 독립적이며, 빈의 특성을 나타내는 값들이다.
- main: 주로 사용되는 주요 빈을 나타낼 때 사용.
- EMEA: 특정 지역(예: 유럽, 중동, 아프리카)과 관련된 빈을 나타낼 때 사용.
- persistent: 영속성 관련 빈을 나타낼 때 사용.
이러한 값들은 빈 ID와 독립적이며, 빈의 특정 특성을 나타내므로, @Qualifier 값으로 사용하는 것이 좋다.
▷ 요약
- 빈 이름은 자격 값으로 간주될 수 있으며, @Qualifier 없이도 주입할 수 있다.
- @Qualifier는 여러 타입 일치 후보 중에서 특정 특성을 가진 빈을 선택할 때 사용된다.
- 좋은 @Qualifier 값은 빈 ID와 독립적이며, 빈의 특성을 나타내는 값들이다.
- 빈 이름을 통해 특정 빈을 참조할 때, 스프링은 타입 기반 주입을 우선시하며, 자격 값은 타입 일치 후보 내에서만 의미가 있다.
qualifier 값은 앞서 논의한 것처럼 타입이 지정된 컬렉션에도 적용될 수 있다. 예를 들어 Set<MovieCatalog>와 같은 경우, 선언된 qualifier 값에 따라 모든 일치하는 빈이 컬렉션으로 주입된다. 이는 qualifier 값이 고유할 필요는 없으며, 필터링 기준으로 작용함을 의미한다. 예를 들어 여러 MovieCatalog 빈을 "action"이라는 동일한 qualifier 값으로 정의하고, @Qualifier("action")이 지정된 Set<MovieCatalog>에 모두 주입할 수 있다.
▶ @Qualifier와 컬렉션 주입
스프링에서 @Qualifier를 사용하는 것은 여러 빈 중에서 특정한 자격 값 (qualifier)을 가진 빈을 선택할 수 있는 방법이다.
주로 타입 기반 주입에서 발생하는 여러 후보 빈을 필터링할 떄 사용된다.
즉, 이러한 @Qualifier가 타입이 지정된 컬렉션 (Set<MovieCatalog>)에도 적용될 수 있음을 말한다. 즉, 여러 개의 빈이 같은 타입을 가질 떄, 자격 값이 같은 빈들을 한꺼번에 컬렉션으로 주입할 수 있다는 뜻이다.
▷ 자격 값이 같은 빈들을 컬렉션에 주입할 수 있는 이유
@Qualifier는 빈의 고유한 특성을 나타내는데 사용되며, 반드시 고유하지 않아도 된다. 즉, 여러 개의 빈이 같은 자격 값을 가질 수 있다. 이 경우 컬렉션 타입의 필드에 같은 자격 값을 가진 모든 빈을 주입할 수 있다.
- 이 방식은 자격 값이 고유할 필요가 없으며, 자격 값이 같은 빈들을 한 그룹으로 묶어 필터링할 수 있다는 점에서 매우 유용합니다.예를 들어, MovieCatalog라는 타입의 빈이 있고, 그중 몇몇 빈들이 "action"이라는 자격 값을 가진다면, @Qualifier("action")을 사용하여 이 빈들을 모두 한꺼번에 Set<MovieCatalog>에 주입할 수 있다.
- 이 방식은 자격 값이 고유할 필요가 없으며, 자격 값이 같은 빈들을 한 그룹으로 묶어 필터링할 수 있다는 점에서 매우 유용하다.
▷ 실제 예시
예를 들어, 두 개의 MovieCatalog 빈이 있다고 가정한다. 각각 액션 장르를 나타내며 "action"이라는 자격 값을 가진다.
@Bean
@Qualifier("action")
public MovieCatalog actionMovieCatalog1() {
return new ActionMovieCatalog1();
}
@Bean
@Qualifier("action")
public MovieCatalog actionMovieCatalog2() {
return new ActionMovieCatalog2();
}
위와 같이 두 개의 액션 장르 빈을 정의한 후, @Qualifier("action")이 지정된 Set<MovieCatalog>에 주입할 수 있다.
@Autowired
@Qualifier("action")
private Set<MovieCatalog> actionMovieCatalogs;
Spring은 Set<MovieCatalog>에 "action" 자격 값을 가진 모든 MovieCatalog 빈을 자동으로 주입한다. 그 결과, 두 개의 액션 영화 카탈로그가 컬렉션에 주입되며, 이 컬렉션을 통해 각 카탈로그에 접근할 수 있다.
▷ 컬렉션 주입의 장점
- 유연성: 여러 개의 빈을 동일한 자격 값으로 그룹화하고, 한꺼번에 컬렉션에 주입할 수 있다. 이를 통해 특정 특성을 가진 빈들을 한꺼번에 관리할 수 있다.
- 확장성: 새로운 빈이 추가되더라도 같은 자격 값만 부여하면 자동으로 컬렉션에 포함된다.
- 필터링 기능: 자격 값은 고유할 필요가 없기 때문에 필터링 기준으로 사용될 수 있다. 예를 들어, 여러 개의 빈이 "action" 자격 값을 가질 수 있으며, 이들을 묶어서 처리할 수 있다.
▷ 자격 값의 역할
자격 값 (@Qualifier)은 빈의 특정 특성을 나타내는 역할을 한다. 자격 값은 다음과 같은 상황에서 유용하게 사용된다.
- 동일한 타입의 여러 빈이 존재할 때, 주입할 빈을 선택해야 하는 상황.
- 여러 빈 중 특정 특성을 공유하는 그룹의 빈들을 한꺼번에 처리해야 하는 상황.
- 컬렉션을 통해 빈을 주입할 때, 특정 자격 값을 가진 빈들만 필터링하여 주입해야 하는 상황.
자격 값은 고유할 필요가 없으며, 빈들을 그룹화하거나 필터링하는데 사용할 수 있다. 예를 들어, "action"이라는 자격 값을 가진 모든 빈을 한꺼번에 주입하거나 처리할 수 있다.
▷ 정리
- @Qualifier는 여러 개의 빈 중에서 특정 자격 값을 가진 빈을 주입하는 데 사용된다.
- 자격 값은 반드시 고유하지 않아도 되며, 여러 빈이 동일한 자격 값을 가질 수 있다.
- 컬렉션 타입의 필드에 같은 자격 값을 가진 모든 빈을 한꺼번에 주입할 수 있습니다. 이는 주로 특정 특성을 공유하는 빈들을 그룹화하여 관리할 때 유용하다.
- 예를 들어, "action"이라는 자격 값을 가진 여러 MovieCatalog 빈들을 Set<MovieCatalog>에 주입할 수 있으며, 이를 통해 특정 장르의 영화를 처리할 수 있다.
타입 일치 후보 내에서 qualifier 값이 대상 빈 이름과 일치하게 하려면 주입 지점에 @Qualifier 어노테이션이 필요하지 않다. 다른 해결 인디케이터(qualifier나 primary marker)가 없는 경우, Spring은 주입 지점 이름(즉, 필드 이름이나 파라미터 이름)을 대상 빈 이름과 일치시켜 동일한 이름의 후보를 선택한다. 6.1 버전부터, Java 컴파일러에서 -parameters 플래그를 지정해야 한다.
▷ @Qualifier가 없어도 이름을 통한 주입 가능
스프링에서 자동 주입 (autowiring)은 주로 타입을 기반으로 이루어진다. 하지만 같은 타입의 여러 빈이 있을 때, 어떤 빈을 주입할지 결정하는 방법이 필요하다. 이를 해결하기 위한 방법 중 하나가 @Qualifier 어노테이션이다. 하지만, @Qualifier를 사용하기 않고도 빈 이름과 필드 이름 또는 파라미터 이름이 일치하면 스프링이 이를 자동으로 연결할 수 있다.
- 주입 지점 이름 (즉, 필드 이름이나 파라미터 이름)이 빈 이름과 일치하면, 스프링은 그 빈을 주입한다.
- 이 방법은 다른 해결 인디케이터 (@Qualifier, @Primary)가 없을 때 동작한다.
예를 들어, 빈 이름이 myMovieCatalog인 빈이 있고, 필드 이름이 myMovieCatalog인 필드가 있다면, @Qualifier 없이도 해당 빈이 필드에 주입된다.
▷ 필드 이름을 기준으로 빈 주입
▼ 필드 이름을 통한 자동 주입 예시 (빈 정의)
@Bean(name = "myMovieCatalog")
public MovieCatalog movieCatalog() {
return new MovieCatalogImpl();
}
위와 같이 myMovieCatalog라는 이름의 빈이 존재할 때, 필드 이름이 myMovieCatalog인 필드에 자동으로 주입할 수 있다.
▼ 필드 이름을 통한 자동 주입 예시 (빈 정의)
public class MovieRecommender {
@Autowired
private MovieCatalog myMovieCatalog; // 필드 이름이 'myMovieCatalog'로 빈 이름과 동일
public void recommendMovies() {
myMovieCatalog.displayMovies();
}
}
이 경우, @Qualifier 없이도 필드 이름과 빈 이름이 일치하기 때문에, Spring은 myMovieCatalog 빈을 자동으로 주입한다.
▷ 파라미터 이름을 기준으로 빈 주입
마찬가지로 생성자나 메서드 파라미터의 이름도 빈 이름과 일치하면, @Qualifier 없이 주입이 가능하다.
▼ 파라미터 이름을 통한 자동 주입
public class MovieRecommender {
private final MovieCatalog myMovieCatalog;
@Autowired
public MovieRecommender(MovieCatalog myMovieCatalog) { // 파라미터 이름이 'myMovieCatalog'
this.myMovieCatalog = myMovieCatalog;
}
public void recommendMovies() {
myMovieCatalog.displayMovies();
}
}
이 경우에도 파라미터 이름이 myMovieCatalog이고, 빈 이름도 myMovieCatalog라면, @Qualifier 없이도 주입된다.
▷ 자바 컴파일러 플래그 -parameters의 필요성
Spring 6.1부터는 파라미터 이름을 통해 주입할 때, Java 컴파일러의 -parameters 플래그가 필요하다. 이 플래그는 파라미터 이름 정보를 런타임에 유지하도록 하는 역할을 한다. 즉, Spring이 파라미터 이름을 확인하고, 빈 이름과 일치하는지 확인할 수 있게 한다.
아래와 같이 메이븐 프로젝트에서 pom.xml에 컴파일러 플러그인을 추가하여 이 플래그를 사용할 수 있다.
▼ Maven 설정에서 -parameters 플래그 추가하기
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source> <!-- Java 버전 지정 -->
<target>17</target> <!-- Java 버전 지정 -->
<compilerArgs>
<arg>-parameters</arg> <!-- 파라미터 이름을 유지하는 플래그 -->
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
이 플래그를 추가하면 생성자나 메서드의 파라미터 이름이 컴파일된 클래스 파일에 포함되며, Spring은 이를 사용해 빈 이름과 파라미터 이름이 일치하는지 확인할 수 있다.
▷ 빈 이름과 @Qualifier의 차이점
@Qualifier는 빈 이름과 상관없이 특정 자격 값을 사용하여 주입할 빈을 더 명확하게 지정하는 방법이다. 반면, 빈 이름과 필드/파라미터 이름이 일치할 때는 굳이 @Qualifier가 필요하지 않다.
- @Qualifier 사용 시: 빈의 특정 속성을 기반으로 빈을 선택하고, 빈 이름과 관계없이 작동한다.
- 이름을 통한 주입 시: 빈 이름이 필드/파라미터 이름과 일치할 때 주입됩니다. 자격 값을 명시하지 않아도 된다.
▷ 요약
- Spring에서는 필드 이름이나 파라미터 이름이 빈 이름과 일치할 때, @Qualifier 없이 빈을 주입할 수 있다.
- 이 방식은 타입 일치 후보 내에서 다른 해결 인디케이터(예: @Qualifier, @Primary)가 없는 경우에만 동작한다.
- Java 컴파일러 플래그 -parameters는 Spring 6.1 이상에서 파라미터 이름을 통한 주입을 가능하게 하며, 이는 파라미터 이름 정보를 유지하기 위해 필요하다.
이 방식은 코드의 가독성을 높이고, 필드 이름이나 파라미터 이름이 빈 이름과 일치하는 경우, 불필요하게 @Qualifier를 사용할 필요가 없다는 장점이 있다.
이름에 의한 주입의 대안으로 JSR-250의 @Resource 어노테이션을 사용할 수 있으며, 이는 선언된 타입이 일치 여부에 영향을 주지 않고 고유한 이름으로 특정 구성 요소를 식별하도록 정의되어 있다. @Autowired는 전혀 다른 의미를 가진다.
후보 빈을 타입으로 먼저 선택한 후, 지정된 문자열 qualifier 값은 타입 선택된 후보 내에서만 고려됩니 (account qualifier가 동일한 qualifier 레이블이 표시된 빈과 일치하는 경우).
컬렉션, 맵, 배열 타입으로 정의된 빈의 경우, @Resource는 해당 컬렉션 또는 배열 빈을 고유한 이름으로 참조하는 좋은 해결책이 될 수 있다. 하지만 Spring 4.3부터는 @Autowired 타입 일치 알고리즘을 사용하여 컬렉션, 맵, 배열 타입을 일치시킬 수 있으며, 엘리먼트 타입 정보가 @Bean 리턴 타입 시그니처 또는 컬렉션 상속 계층에서 보존되는 한 가능합니다. 이 경우 qualifier 값은 동일한 타입의 컬렉션 중에서 선택할 때 사용할 수 있다.
Spring 4.3부터는 @Autowired가 자기 참조를 위한 주입도 고려한다(즉, 현재 주입된 빈을 다시 참조). 자기 참조는 최후의 수단이다. 다른 구성 요소에 대한 일반적인 의존성이 항상 우선한다. 즉, 자기 참조는 정규 후보 선택에 참여하지 않으며, 기본적으로 절대 우선순위가 아니다. 반대로, 항상 가장 낮은 우선순위로 끝난다. 실무에서는 자기 참조를 최후의 수단으로만 사용해야 하며(트랜잭션 프록시를 통해 같은 인스턴스의 다른 메서드를 호출하는 경우), 해당 메서드를 별도의 위임 빈으로 분리하는 것을 고려해야 한다. 대안으로, @Resource를 사용하여 고유한 이름으로 현재 빈에 대한 프록시를 얻을 수 있다.
같은 구성 클래스에 있는 @Bean 메서드의 결과를 주입하려는 시도도 사실상 자기 참조 시나리오다. 이러한 참조는 실제로 필요한 메서드 시그니처 내에서 지연 해결하거나, 관련된 @Bean 메서드를 static으로 선언하여 해당 구성 클래스 인스턴스와 생명 주기에서 분리해야 한다. 그렇지 않으면, 이러한 빈은 후속 단계에서만 고려되며, 다른 구성 클래스에 있는 일치하는 빈이 기본 후보로 선택된다 (사용 가능한 경우).
@Autowired는 필드, 생성자 및 다중 아규먼트 메서드에 적용되며, 파라미터 레벨에서 qualifier 어노테이션을 통해 좁힐 수 있다. 반면에, @Resource는 단일 아규먼트를 가진 필드와 빈 속성 세터 메서드만 지원한다. 따라서 주입 대상이 생성자이거나 다중 아규먼트 메서드인 경우 qualifier 를 사용하는 것이 좋다.
사용자 정의 qualifier 어노테이션도 만들 수 있습니다. 이를 위해 어노테이션을 정의하고, 그 정의 내에 @Qualifier 어노테이션을 제공하면 됩니다. 다음 예제는 이를 보여준다.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
String value();
}
그런 다음 사용자 정의 qualifier을 @Autowired 필드와 파라미터에 제공할 수 있다.
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 어노테이션에 맞는 타입과 값을 지정할 수 있다. 타입은 어노테이션의 완전한 클래스 이름과 일치해야 한다. 편의를 위해 이름 충돌의 위험이 없으면 짧은 클래스 이름을 사용할 수도 있다. 다음 예제는 두 가지 방법을 모두 보여준다.
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action
"/>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="example.Genre" value="Comedy"/>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
Classpath Scanning and Managed Components에서는 어노테이션 기반 대안을 통해 qualifier 메타데이터를 제공하는 방법을 확인할 수 있다. 특히, Providing Qualifier Metadata with Annotations를 참조하면 좋다.
일부 경우에는 값이 없는 어노테이션을 사용하는 것으로 충분할 수 니다. 이 방법은 어노테이션이 더 일반적인 목적을 가지고 여러 다른 타입의 의존성에 적용될 수 있을 때 유용할 수 있다. 예를 들어, 인터넷 연결이 없을 때 사용할 수 있는 오프라인 카탈로그를 제공할 수 있다. 먼저, 간단한 어노테이션을 정의한다.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
그런 다음 주입할 필드나 속성에 어노테이션을 추가한다.
public class MovieRecommender {
@Autowired
@Offline
private MovieCatalog offlineCatalog;
// ...
}
이제 빈 정의에는 qualifier 타입만 필요하다.
<bean class="example.SimpleMovieCatalog">
<qualifier type="Offline"/>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
사용할 qualifier 를 지정하는 요소다. 또한 간단한 값 속성 대신 명명된 속성을 허용하는 사용자 정의 자격 어노테이션도 정의할 수 있다. 여러 속성 값이 주입 대상 필드나 파라미터에 지정된 경우, 빈 정의는 그러한 속성 값을 모두 일치시켜야 주입 후보로 간주된다.
@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로 어노테이션되고, genre와 format 속성에 대한 값을 포함한다.
public class MovieRecommender {
@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;
@Autowired
@MovieQualifier(format=Format.VHS, genre="Comedy")
private MovieCatalog comedyVhsCatalog;
@Autowired
@MovieQualifier(format=Format.DVD, genre="Action")
private MovieCatalog actionDvdCatalog;
@Autowired
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
private MovieCatalog comedyBluRayCatalog;
// ...
}
마지막으로, 빈 정의는 일치하는 qualifier 값으로 구성되어야 한다. 이 예제는 또한 <qualifier/> 요소 대신 빈 메타 속성을 사용할 수 있음을 보여준다. 사용할 수 있는 경우, <qualifier/> 요소와 그 속성이 우선 순위를 차지하지만, 이러한 qualifier가 없으면 자동 주입 메커니즘은 마지막 두 빈 정의에서 볼 수 있듯이 <meta/> 태그에 제공된 값으로 대체된다.
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Action"/>
</qualifier>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Comedy"/>
</qualifier>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="DVD"/>
<meta key="genre" value="Action"/>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="BLURAY"/>
<meta key="genre" value="Comedy"/>
<!-- 이 빈에 필요한 의존성 주입 -->
</bean>
</beans>
'스프링 프레임워크 > IoC (Inversion of Control)' 카테고리의 다른 글
Using the @Configuration annotation (0) | 2024.11.19 |
---|---|
Using the @Bean Annotation (0) | 2024.11.19 |
Instantiating the Spring Container by Using AnnotationConfigApplicationContext (0) | 2024.11.19 |
Annotation-based Container Configuration (0) | 2024.11.19 |
Bean Scopes (0) | 2024.11.18 |