[Spring] 스프링(Spring) @Qualifier, @Named, @Primary 의존객체 선택
| 스프링 의존객체 선택(Select Spring Dependency Object)
@Autowired, @Resource, @Inject 어노테이션으로만 자동적으로 객체를 주입할 경우 컨테이너에서 주입할 대상이 여러개여서 의존성을 주입하지 못하는 경우가 발생할 수 있다.
다음과 같이 @Autowired를 통해 객체를 주입하려고 할 때, 컨테이너상에서는 Weapon 인터페이스를 상속한 2개의 bean 객체인 gun과 knife가 존재한다. @Autowired는 먼저 Type을 기준으로 주입할 객체를 정하기 때문에 같은 Type이 스프링 컨테이너 상에 존재할 경우 에러를 내게 된다.
appContext.xml
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:annotation-config/>
<bean id="gun" class="com.tutorial.spring.Gun"/>
<bean id="knife" class="com.tutorial.spring.Knife"/>
<bean id="gunPlayer" class="com.tutorial.spring.Player"/>
<bean id="gunPlayer2" class="com.tutorial.spring.Player2"/>
</beans>
public class Player {
@Autowired
private Weapon weapon;
Player(){
}
public Player(Weapon weapon) {
super();
this.weapon = weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public Weapon getWeapon() {
return weapon;
}
public void usePlayerWeapon() {
weapon.useWeapon();
}
public void setPlayerWeaponNow(Weapon weapon) {
}
}
// 결과
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gunPlayer': Injection of autowired dependencies failed; nested exception is ...
... (생략 ) ...
이 때, @Qualifier나 @Named 어노테이션을 써서 하나의 의존객체를 선택하여 객체 간 선택적 충돌이 발생하지 않게 할 수 있다.
| @Qualifier
@Qualifier는 저번 포스팅에서도 잠시 언급한 적이 있다. @Qualifier는 @Autowired와 같이 쓰이며 여러개의 타입이 일치하는 bean객체가 있을 경우 @Qualifier 어노테이션의 유무를 확인한 후 조건에 만족하는 객체를 주입하게 된다.
appContext.xml
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:annotation-config/>
<bean id="gun" class="com.tutorial.spring.Gun">
<qualifier value="gunner"></qualifier> <-- Qualifier를 명시한다 -->
</bean>
<bean id="knife" class="com.tutorial.spring.Knife"/>
<bean id="gunPlayer" class="com.tutorial.spring.Player"/>
<bean id="gunPlayer2" class="com.tutorial.spring.Player2"/>
</beans>
import javax.inject.Inject;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Player {
@Autowired
@Qualifier("gunner") // appContext.xml 에 명시했던 qulifier name을 쓴다
private Weapon weapon;
Player(){
}
public Player(Weapon weapon) {
super();
this.weapon = weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public Weapon getWeapon() {
return weapon;
}
public void usePlayerWeapon() {
weapon.useWeapon();
}
public void setPlayerWeaponNow(Weapon weapon) {
}
}
public class Main {
public static void main(String[] args) {
String xmlConfigPath = "classpath:appContext.xml";
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(xmlConfigPath);
Player gunPlayer = ctx.getBean("gunPlayer", Player.class);
gunPlayer.usePlayerWeapon();
}
}
| @Named
@Named는 @Inject와 함께 쓰이며 @Qualifier와 달리 xml 컨테이너 설정파일에 다른 정보를 명시할 필요 없이 기존의 bean객체의 ID를 가지고 객체를 명시적으로 선택하게 된다.
appContext.xml
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:annotation-config/>
<bean id="gun" class="com.tutorial.spring.Gun">
</bean>
<bean id="knife" class="com.tutorial.spring.Knife"/>
<bean id="gunPlayer" class="com.tutorial.spring.Player"/>
<bean id="gunPlayer2" class="com.tutorial.spring.Player2"/>
</beans>
package com.tutorial.spring;
import javax.inject.Inject;
import javax.inject.Named;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Player {
@Inject
@Named("gun") // 스프링 컨테이너 xml 설정파일에 명시되어 있는 ID를 적음
private Weapon weapon;
Player(){
}
public Player(Weapon weapon) {
super();
this.weapon = weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public Weapon getWeapon() {
return weapon;
}
public void usePlayerWeapon() {
weapon.useWeapon();
}
public void setPlayerWeaponNow(Weapon weapon) {
}
}
public class Main {
public static void main(String[] args) {
String xmlConfigPath = "classpath:appContext.xml";
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(xmlConfigPath);
Player gunPlayer = ctx.getBean("gunPlayer", Player.class);
gunPlayer.usePlayerWeapon();
}
}
| @Primary
@Primary로 같은 우선순위로 있는 클래스가 여러개가 있을 시 그 중 가장 우선순위로 주입할 클래스 타입을 선택할 수 있다.
@Repository @Primary
public class BSRepository implements BookRepository {
}
'Spring Framework > Spring 입문 - 개념 및 핵심' 카테고리의 다른 글
[Spring] Eclipse 톰캣(Tomcat) 연동 및 STS 설치, Spring MVC 프로젝트 생성 (0) | 2021.01.14 |
---|---|
[Spring] 스프링(Spring) MVC 아키텍처/설계 구조 (0) | 2020.12.21 |
[Spring] 어노테이션(Annotation)을 이용한 스프링 설정 (0) | 2020.12.21 |
[Spring] 스프링 컨테이너(Spring Container)와 빈(Bean) 객체 생명 주기 및 init-method, destroy-method, @PostConstruct, @PreDestroy (0) | 2020.12.17 |
[Spring] 의존객체 자동 주입(Automatic Dependency Injection), @Autowired, @Resource, @Inject (0) | 2020.12.17 |
[Spring] 스프링 빈 범위 지정(Spring Bean Scope), 싱글턴(Singleton), 프로토타입(Prototype) (0) | 2020.12.17 |
[Spring] 여러개로 나뉜 Spring XML 설정파일 합치기 (0) | 2020.12.17 |
[Spring] Spring에서 새터(Setter)로 리스트(List), 맵(Map) 자료구조 주입 (0) | 2020.12.17 |