@Autowired는 기본적으로 Type으로 조회 하기 때문에 같은 역할(Interface)를 구현하는 빈이 두개라면 충돌해 에러가 발생합니다. 이러한 문제를 해결하는 방법들이 있는데 이 방법들을 하나씩 정리해 보려고 합니다.
우선 결론부터 이야기 하자면 @Primary, @Qualifier를 사용하면 되고, 둘의 우선순위는 더 구체적으로 명시하는 @Qualifier 가 우선순위가 더 높습니다.
이제 하나하나 살펴봅시다.
예시를 들기 위해 보이지는 않지만 Repository 역할을 구현한 객체 2개를 중복해서 빈으로 등록해 두었는데요. (MyRepository, MyNewRepository)
위와같이 Repository 인터페이스를 구현한 객체가 2 이상이라면 의존관계 주입시에 에러가 발생 할 것입니다. 이 경우 아래와 같이 필드명, 혹은 매개변수의 이름을 바꾸어주면 빈이 중복으로 있더라도 바꾼 이름과 일치하는 빈을 찾아 의존관계를 주입해 줍니다.
위와 같은 방법이 가능한 이유는 @Autowired로 빈을 주입할 때 우선 명시된 타입의 빈을 찾고, 중복등의 이유로 의존관계 주입이 어려우면 그 다음으로는 필드명이나 매개변수명의 이름을 가진 빈을 찾아 등록하는 과정으로 의존관계 주입이 일어나기 때문입니다.
1. 타입으로 매칭
2. 같은 타입이 2개 이상이면 필드명, 파라미터 명으로 빈 이름 매칭
@Qualifier는 태그를 붙여주는 것과 같습니다. 빈 등록시에 @Qualifier로 태그를 명시해 주고 이후에 의존관계 주입을 받을 때 동일한 태그를 붙여주면 같은 타입의 여러개의 빈이 중복 되더라도 동일한 태그의 빈을 의존관계로 주입받을 수 있습니다.
위와같이 빈으로 등록될 객체에 @Qualifier를 추가해주고,
의존관계를 명시할 때 동일한 이름의 @Qualifier를 추가해 주어 의존관계를 확정 지어줄 수 있습니다.
@Qualifier를 사용하기 위해서는 String으로 구분할 값을 명시해야하는데 String의 문제는 컴파일러가 오류를 체크하지 못한다는 단점이 있습니다.
이러한 점을 개선하기 위해 간단한 방법으로 새로운 어노테이션을 만들어 지정해 줄 수 있습니다.
우선, 새로운 이름으로 어노테이션을 하나 생성합니다
예) @MyMainRepository
그리고 @Qualifier에 존재하는 어노테이션들을 끌어다 붙여주고 그 아래에 원하는 @Qualifier 어노테이션을 추가해줍니다.
이후 해당 어노테이션을 기존에 쓰던 @Qualifier 위치에 넣어 사용하면 됩니다.
❓ 무슨 차이가 있나요??
=> 아래 예시와 같이 String이었다면 잡지 못할 에러를 컴파일러가 잡아서 알려줄 수 있게 됩니다.
@Primary 는 여러개의 중복되는 타입의 빈 객체들중 가장 우선순위를 가진다는 의미의 어노테이션 입니다.
아래와 같이 어노테이션을 추가해주면 Repository의 중복되는 빈들(MyRepository, MyNewRepository) 중에서 MyNewRepository가 의존관계 주입의 대상이 됩니다.
@Qualifier 와 비슷한 기능이지만, @Primary는 원하는 객체에만 추가하면 된다는 점에서
객체와 의존받을 매개변수 두곳에 선언해야하는 @Qualifier 보다는 간편한 장점이 있습니다.