이번 글에서는 @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을 적절히 선택해서 쓰면 된다.