이번 글에서는 @Qualifier
annotation이 뭔지, 어느 상황에서 어떤 용도로 쓰이는지를 알아보도록 하겠다.
사실 이전 두 글들(1, 2)에서 중간 중간 언급을 했기 때문에 그걸 참고해도 좋다. 다만 거기서 안 다룬 내용을 여기서 조금 더 다룬다.
이전에 implicit이 아닌 explicit하게 DI를 해주는 annotation으로 @Autowired
에 대해서 알아봤었다.
다만 이 annotation이 존재해도 spring이 무슨 bean을 주입해야 하는지 이해 못하는 상황이 있을 수 있다고 했다. @Autowired
가 기본적으로 타입을 기반으로 주입하는데, 같은 타입의 bean이 여러개가 있는 경우에 무엇을 주입할지 모른다고 얘기했었다. 예를들어 밑과 같이 Formatter
에 해당하는 bean이 2개 있고 이를 formatter
에 주입 받는 FooService
가 있는 경우가 있다.
@Component("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
@Component
public class FooService {
@Autowired
private Formatter formatter;
}
@Qualifier
을 사용한다.@Qualifier
Annotation매우 간단한 annotation이다. 문장려에 해당하는 value
를 받는다. 해당 값이 일치하는 bean을 autowire등을 통해 주입 받는다는 것을 spring에게 알릴 때 사용된다.
이때 @Qualifier
에 넣는 값이 bean의 무슨 값이랑 일치해야 하냐면
@Qualifier
에 달려있는 이름이랑 일치해야 한다.앞의 예시의 경우 주입받는 측에서 다음과 같이 @Qualifier
annotation을 쓰면 FooFormatter
이라는 bean을 주입받게 된다. 해당 class의 camelcase 이름이 fooFormatter
이기 때문.
public class FooService {
@Autowired
@Qualifier("fooFormatter")
private Formatter formatter;
}
Formatter
에 해당하는 class들의 @Component
밑에 다음과 같이 @Qualifier
을 달아도 FooService
가 fooFormatter
에 해당하는 bean을 주입받는다.@Component
@Qualifier("fooFormatter")
public class FooFormatter implements Formatter {
//...
}
@Component
@Qualifier("barFormatter")
public class BarFormatter implements Formatter {
//...
}
@Qualifier
vs. @Primary
@Primary
사실 DI를 통해 주입해야 할 bean을 뭘로 할지 애매할 때 판별하는 annotation으로 @Primary
라는 녀석도 존재한다.
어떤 class가 특정 타입의 bean을 주입받아야 하는데 모든 규칙을 적용한 후에도 주입받을 수 있는 해당 타입의 bean이 여러개이면, @Primary
가 달려있는 bean을 우선으로 주입받는다.
예를 들어 밑과 같이 2개의 Employee
bean을 만드는 @Configuration
class를 봐보자.
@Configuration
public class Config {
@Bean
public Employee johnEmployee() {
return new Employee("John");
}
@Bean
@Primary
public Employee tonyEmployee() {
return new Employee("Tony");
}
}
이러면 어떤 class가 Employee
라는 bean을 주입받으려 하고 특별히 추가 명시를 하지 않으면 tonyEmployee
가 주입받게 된다.
유의할건 앞에서 계속 언급했듯이, 다른 추가 명시가 없을 때 @Primary
가 주입된다는 것이다. 이는 다른 말로 @Primary
보다 우선순위가 높은 annotation을 사용시에 그걸 우선시해서 주입한다는 것이고, 그 중 하나가 @Qualifier
이다.
즉 @Qualifier
이랑 @Primary
가 혼용되면 기본 주입 bean이 @Primary
이고, 때때로 @Qualifier
을 활용해 다른 bean을 주입하는 것이라고 생각하면 된다.
참고로 3번의 예제도 @Qualifier
대신 @Primary
를 통해 구현하는게 가능하다. 밑의 예시 참고.
@Component
@Primary
public class FooFormatter implements Formatter {
//...
}
@Component
public class BarFormatter implements Formatter {
//...
}
@Component
public class FooService {
@Autowired
private Formatter formatter;
}
@Qualifier
vs. Autowiring by Name@Qualifier
이 없으면 이름을 기반으로 주입한다고 했었다. 이때 이름은 class의 이름이 아닌 bean의 이름이라는 점 참고. 밑은 이를 활용해 @Qualifier
없이 fooFormatter
이름의 bean을 주입받는 것이다.@Component
public class FooFormatter implements Formatter {
//...
}
@Component
public class BarFormatter implements Formatter {
//...
}
public class FooService {
@Autowired
private Formatter fooFormatter;
}
@Qualifier
이랑 이름 기반 autowiring을 적절히 선택해서 쓰면 된다.