In this tutorial, we will see how to use Spring or Spring Boot @Qualifier annotation to resolve ambiguous dependencies.
The @Qualifier
annotation is used in conjunction with @Autowired to avoid confusion when we have two or more
beans configured for the same type.
If there are multiple implementations for a single interface then we can use @Qualifier
to choose the required implementation at runtime.
Let's take a Message Processing Example - a message can be sent in many ways like Email, SMS, Twitter, etc.
Let's create a MessageService
interface for multiple message service
implementations - EmailService
,
SMSService
, and TwitterService
classes.
public interface MessageService {
public void sendMsg(String message);
}
Next, let's create implementations - EmailService
, SMSService
, and TwitterService
classes.
public class EmailService implements MessageService{
public void sendMsg(String message) {
System.out.println(message);
}
}
public class TwitterService implements MessageService{
public void sendMsg(String message) {
System.out.println(message);
}
}
public class SMSService implements MessageService{
public void sendMsg(String message) {
System.out.println(message);
}
}
It's time to see the usage of @Qualifier annotation.
public interface MessageProcessor {
public void processMsg(String message);
}
public class MessageProcessorImpl implements MessageProcessor {
private MessageService messageService;
// setter based DI
@Autowired
@Qualifier("twitterService")
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}
// constructor based DI
@Autowired
public MessageProcessorImpl(@Qualifier("twitterService") MessageService messageService) {
this.messageService = messageService;
}
public void processMsg(String message) {
messageService.sendMsg(message);
}
}
In the above example, Dependency is injected by both setter and constructor so you can use either one of them.
We have used @Qualifier
to inject TwitterService
bean using constructor injection:
// setter based DI
@Autowired
@Qualifier("twitterService")
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}
We have used @Qualifier
to inject the TwitterService
bean using setter injection:
// constructor based DI
@Autowired
public MessageProcessorImpl(@Qualifier("twitterService") MessageService messageService) {
this.messageService = messageService;
}
If you want to inject EmailService bean instead of TwitterService bean then you can simply pass bean EmailService bean name. For example:
// constructor based DI
@Autowired
public MessageProcessorImpl(@Qualifier("emailService") MessageService messageService) {
this.messageService = messageService;
}
Let's write the java based configuration.
@Configuration
@ComponentScan("com.javadevsguide.springframework.di")
public class AppConfiguration {
@Bean(name="emailService")
public MessageService emailService(){
return new EmailService();
}
@Bean(name="twitterService")
public MessageService twitterService(){
return new TwitterService();
}
@Bean(name="smsService")
public MessageService smsService(){
return new SMSService();
}
@Bean
public MessageProcessor messageProcessor(){
return new MessageProcessorImpl(twitterService());
}
}
Let's test the example using the Spring IOC container which is an ApplicationContext object.
public class TestApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfiguration.class);
MessageProcessor processor = applicationContext.getBean(MessageProcessor.class);
processor.processMsg("twitter message sending ");
}
}
Output:
twitter message sending
In this example, we have seen how to use @Qualifier
annotation in
conjunction with @Autowired to avoid
confusion when we have two or more beans configured for the same type.