Using @Primary and @Qualifier in Spring Boot with Full Example

1 min read

Using @Primary and @Qualifier in Spring Boot with Full Example

Spring Boot provides powerful dependency injection features, allowing developers to manage beans effectively. Two key annotations, @Primary and @Qualifier, help resolve conflicts when multiple beans of the same type exist. In this article, we’ll explore their usage with a full example.

Understanding @Primary and @Qualifier

  • @Primary: Marks a bean as the default choice when multiple beans of the same type are available.
  • @Qualifier: Specifies the exact bean to inject, overriding the default behavior of @Primary.

Example Scenario

Let’s consider a scenario where we have multiple implementations of a PaymentService interface: CreditCardPaymentService and PayPalPaymentService.

Step 1: Define the Interface

public interface PaymentService {
    void processPayment(double amount);
}

Step 2: Implement Multiple Beans

import org.springframework.stereotype.Service;

@Service
public class CreditCardPaymentService implements PaymentService {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing credit card payment of $" + amount);
    }
}
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Primary;

@Primary // This makes CreditCardPaymentService the default bean
@Service
public class PayPalPaymentService implements PaymentService {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing PayPal payment of $" + amount);
    }
}

Step 3: Inject the Default Bean Using @Primary

import org.springframework.stereotype.Component;

@Component
public class PaymentProcessor {
    private final PaymentService paymentService;

    public PaymentProcessor(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void makePayment(double amount) {
        paymentService.processPayment(amount);
    }
}

Since PayPalPaymentService is marked with @Primary, it will be injected by default.

Step 4: Override @Primary Using @Qualifier

import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Qualifier;

@Component
public class AlternativePaymentProcessor {
    private final PaymentService paymentService;

    public AlternativePaymentProcessor(@Qualifier("creditCardPaymentService") PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void makePayment(double amount) {
        paymentService.processPayment(amount);
    }
}

Here, @Qualifier("creditCardPaymentService") ensures CreditCardPaymentService is injected instead of the default PayPalPaymentService.

Step 5: Run the Application

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class PaymentApplication implements CommandLineRunner {
    private final PaymentProcessor paymentProcessor;
    private final AlternativePaymentProcessor alternativePaymentProcessor;

    public PaymentApplication(PaymentProcessor paymentProcessor, AlternativePaymentProcessor alternativePaymentProcessor) {
        this.paymentProcessor = paymentProcessor;
        this.alternativePaymentProcessor = alternativePaymentProcessor;
    }

    public static void main(String[] args) {
        SpringApplication.run(PaymentApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        paymentProcessor.makePayment(100.0); // Uses PayPalPaymentService
        alternativePaymentProcessor.makePayment(200.0); // Uses CreditCardPaymentService
    }
}

Output

Processing PayPal payment of $100.0
Processing credit card payment of $200.0

Conclusion

By using @Primary, we set a default bean, and @Qualifier allows us to specify a different implementation when needed. This approach gives flexibility in managing multiple bean implementations within a Spring Boot application.

🤞 Never miss a story from us, get weekly updates to your inbox!