Difference Between Spring @Qualifier and @Primary Annotations

In Spring Framework, dependency injection plays a vital role in managing the application's components. However, in situations where multiple beans of the same type exist, it can create ambiguity during autowiring. Spring provides two annotations, @Qualifier and @Primary, to tackle such scenarios and ensure precise bean injection.
 
In this blog post, we will explore the differences between these annotations and demonstrate their use with practical examples.

@Qualifier Annotation

The @Qualifier annotation is used to resolve ambiguity when multiple beans of the same type are present in a Spring application context. It allows you to specify a specific bean to be injected by using a qualifier value.

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.

For example, consider we have a MessageService interface with multiple implementations - EmailServiceSMSService, and TwitterService classes.

MessageService interface

public interface MessageService {
    public void sendMsg(String message);
}
Next, let's create implementations - EmailServiceSMSService, and TwitterService classes.

EmailService Class

public class EmailService implements MessageService{

    public void sendMsg(String message) {
         System.out.println(message);
    }
}

SMSService Class

public class TwitterService implements MessageService{

    public void sendMsg(String message) {
        System.out.println(message);
    }
}

TwitterService Class

public class SMSService implements MessageService{

    public void sendMsg(String message) {
         System.out.println(message);
    }
}

MessageProcessor Interface and MessageProcessorImpl Class

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;
    }
Check out complete code example: Spring @Qualifier Annotation Example

@Primary Annotation

The @Primary annotation is used to indicate a default bean when multiple beans of the same type are present. If multiple beans are eligible for autowiring and none of them are explicitly specified using @Qualifier, the bean marked with @Primary will be selected by default.

Suppose we have two beans implementing the MailSender interface - EmailSender and SmsSender. To set EmailSender as the default bean for autowiring, we can use the @Primary annotation.
@Component
@Primary
public class EmailSender implements MailSender {
    // ...
}

@Component
public class SmsSender implements MailSender {
    // ...
}

@Service
public class NotificationService {
    @Autowired
    private MailSender mailSender;
    // ...
}
Complete code example: Spring @Primary Annotation Example

Conclusion

To summarize, the @Qualifier annotation is used to resolve ambiguity when multiple beans of the same type exist, whereas the @Primary annotation designates a default bean to be injected when no qualifier is specified. They serve different purposes and can be used together or individually, depending on the desired behavior of bean injection.

Comments