@Qualifier 어노테이션의 NoUniqueBeanDefinitionException 이슈 문제 해법

어노테이션을 이용하여 의존성을 주입하는 것 중에서 @Qualifier를 사용시 다음과 같은 에러가 발생하는 경우가 있다.

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [polymorphism.Speaker] is defined: expected single matching bean but found 2: apple,sony

에러 메시지에 나와 있는 것 처럼 의존성을 주입할 객체가 2개가 존재한다는 것이다(apple sony). 어떤 경우에서 이런 문제가 발생하는가?

public interface Speaker {
    public void volumeUp();
    public void volumeDown();
}

@Component("apple")
public class AppleSpeaker implements Speaker {
   public AppleSpeaker() {
        System.out.println("▶▶▶▷  Apple Speaker 생성자~~~ 객체 생성 ~~~");
    }
             ... 중 략 ...
}

@Component("sony")
public class SonySpeaker implements Speaker {
    public SonySpeaker() {
        System.out.println("▶▶▶▷  SonySpeaker 생성자 ----- 객체 생성");
    }
             ... 중 략 ...
}

위와 같을 경우 apple라는 id를 가진 AppleSpeaker 객체와 sony라는 id를 가진 SonySpeaker 객체를 Spring 컨테이너가 생성하게 된다.
이 두 객체는 둘 다 Speaker 타입의 인터페이스를 구현한 객체이다. 이를 경우 아래와 같이 Speaker 타입의 객체를 의존성 주입하고자 하면 Speaker 타입을 구현한 2개의 객체가 존재한다(AppleSpeaker, SonySpeaker). 따라서 아래의 speaker 변수에 어느 객체를 주입해야 할지 Spring 컨테이너가 결정할수가 없게된다. 따라서 위와 같은 에러를 발생하게 되는 것이다. 
그런데 이 문제를 해결하기 위해 @Qualifier라는 어노테이션이 존재하는데(혹은 @Resource) 이 어노테이션을 아래와 같이 적용을 해도 여전히 아래와 같은 동일한 에러가 발생한다.

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [polymorphism.Speaker] is defined: expected single matching bean but found 2: apple,sony


@Component
public class LgTV implements TV {

    @Autowired
    @Qualifier("apple")
    // @Resource(name="sony")
    private Speaker speaker;

    public LgTV() {
        System.out.println("▶▶▶▷  LG TV 생성자 ----- 객체 생성 ---");
    }
             ... 중 략 ...
}

이 이슈는 아마도 Spring 자체의 문제인듯하다(정확한건 잘 모르겠지만).
해결 하는 방법은 동일 타입의 객체가 여러개 있을 때 그 중 default로 주입할 클래스(혹은 최 우선 순위로 주입할 객체)를 선택할수 있게 하는 @Primary라는 어노테이션을 동일 타입의 클래스들 중 어느 하나에 지정해 주면 해결된다. 아래와 같이 

@Primary
@Component("apple")
public class AppleSpeaker implements Speaker {
    public AppleSpeaker() {
        System.out.println("▶▶▶▷  Apple Speaker 생성자~~~ 객체 생성 ~~~");
    }
             ... 중 략 ...
}

@Primary를 SonySpeaker 클래스나 AppleSpeaker 클래스느나 둘 중 어느 하나에 지정해 주면 문제가 깔끔하게 해결이 된다. 

+ Recent posts