[ UnsatisfiedDependencyException ]

Error creating bean with name 'galaxy':
Unsatisfied dependency expressed through field 'watch':
No qualifying bean of type 'test06.Watch' available:
expected single matching bean but found 2: aw,sw
Galaxy(galaxy 빈)을 만들 때,
그 안에 있는 필드 watch에 Watch 타입 빈을
주입(Autowired)하려고 했는데
Watch 타입 빈이 2개(aw, sw)나 있어서
뭘 넣어야 할지 Spring이 결정 못했다
→ 그래서 galaxy 생성이 실패했다는 뜻.
[ 코드 구조 ]
public class Client {
public static void main(String[] args) {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
Phone phone = (Phone)factory.getBean("apple");
phone.turnOn();
phone.volumeUp();
phone.volumeDown();
phone.turnOff();
factory.close();
}
}
클라이언트에서는 스프링 컨테이너를 호출 후
apple로 아이폰과 애플워치를 사용하는 구조이다.
[ 아이폰 코드 ]
@Component("apple")
public class IPhone implements Phone {
@Autowired
@Qualifier("aw")
private Watch watch;
호출당한 애플은 문제가 없었다!
오토와이어드와 퀄리파이어로 아이폰에 필요한
애플워치의 의존성 주입을 해결해놨기 때문이다.
(DI 이슈 해결되어 있는 상태)
[ 문제 발생 코드 - 갤럭시 ]
@Component("galaxy")
public class GalaxyPhone implements Phone {
@Autowired
private Watch watch;
클라이언트에서 갤럭시가 호출당하지 않았지만
스프링 컨테이너 세팅에서 문제가 발생한다.
“클라이언트에서 apple만 꺼내도,
스프링은 컨테이너를 만들면서
(= new GenericXmlApplicationContext(...) 하는 순간)
전체 @Component 빈을 다 만들려고 한다.”
그래서 클라이언트가 galaxy를 안 꺼냈어도,
컨테이너 초기화 과정에서 galaxy 생성 시도
→ Watch가 2개라 주입 못함
→ 컨테이너 자체가 실패
→ 결국 apple까지 못 꺼내는 현상 발생
▼ 흐름으로 보면
- new GenericXmlApplicationContext("applicationContext.xml")
→ 여기서 컴포넌트 스캔 + 빈 등록 + (기본적으로) 빈 생성/주입 - 스캔 결과
- IPhone(apple) : @Qualifier("aw") 있어서 주입 가능
- GalaxyPhone(galaxy) : @Autowired Watch watch; 만 있음
→ Watch 타입 빈이 aw, sw 두 개라서 뭘 넣을지 결정 불가
그래서 컨테이너 초기화가 실패하고,
getBean("apple")까지 코드가 못 감.
[ 오류 해결 ]
@Component("galaxy")
public class GalaxyPhone implements Phone {
@Autowired
@Qualifier("sw")
private Watch watch;
스프링 컨테이너가 정상적으로 생성될 수 있도록
호출되지 않는 갤럭시폰 코드에도
퀄리파이어 'sw'를 추가하여 수정하면 된다.

코드 수정 후 정상적으로 작동하는
콘솔 결과를 확인할 수 있다.