Providing the Dependency Injection feature automatically in Spring Boot applications provides great convenience to the developers. In case of multiple services deriving from an interface though, which service will the Spring Boot application inject? In this case, it might not be able to decide which service to inject.
Let’s consider the code below, it provides two different implementations of MessageService:
public interface MessageService {
void printMessage();
}
@Service
public class ShortMessageService implements MessageService{
@Override
public void printMessage() {
System.out.println("ShortMessageService");
}
}
@Service
public class LongMessageService implements MessageService{
@Override
public void printMessage() {
System.out.println("LongMessageService");
}
}
@Service
public class ExecuteMessageService {
@Autowired
private MessageService messageService;
public void getMessage(){
messageService.printMessage();
}
}
The above code gives an error at compile time as we perform the scenario exemplified in the video below.
Field messageService in com.example.demo.ExecuteMessageService required a uniquely identifiable bean, but two equivalent implementations were found.
This error is an example of the situation mentioned above, there are multiple implementations connected to the MessageService interface. Spring Boot couldn’t decide which one to inject.
Annotations are used to quickly solve this problem in Spring Boot applications. There are two annotations that will help us solve this problem. These annotations are Primary and Qualifier. They have some similarities and some differences.
First of all, when we want to solve the problem with the Primary annotation, we should write @Primary at the beginning of the service we want to inject when the MessageService interface is called. For example, if we want the ShortMessageService service to be injected as follows, such an approach can be preferred.
@Primary
@Service
public class ShortMessageService implements MessageService{
@Override
public void printMessage(){
System.out.println("ShortMessageService");
}
}
Then, when we want to solve the problem with the other method, Qualifier annotation, our approach will be slightly different. Where we call the MessageService interface, we can specify which service to inject as a static parameter of the Qualifier annotation.
For example, if we want the LongMessageService service to be injected, we can update the ExecuteMessageService service as follows.
@Service
public class ExecuteMessageService{
@Autowired
@Qualifier("longMessageService")
private MessageService messageService;
public void getMessage(){
messageService.printMessage();
}
}
In the video below, we see that the Spring Boot application is successfully built with two methods separately.
Difference between Qualifier and Primary
Software developers frequently use these two annotations in Spring Boot applications. There is a fundamental difference between these two annotations. If you use the Primary annotation, the same implementation will always be used, this provides more clarity and a more concise code. The Qualifier annotation is more flexible, you can use an implementation of the Service in one class and another in a different class.