How does Spring resolve autowiring ambiguity with @Qualifier and @Primary?

7 minintermediatequalifierprimaryautowiring

Quick Answer

When multiple beans of the same type exist, Spring's default by-type autowiring is ambiguous and fails at startup with a NoUniqueBeanDefinitionException unless disambiguated. @Primary marks one candidate bean as the default choice whenever multiple matches exist. @Qualifier lets the injection point specify exactly which named bean it wants, overriding @Primary when both are present at a given injection site.

Detailed Answer

Spring's default autowiring strategy resolves a dependency by type first. If more than one bean of that type exists, autowiring becomes ambiguous:

interface PaymentGateway { }
@Component class StripeGateway implements PaymentGateway { }
@Component class PayPalGateway implements PaymentGateway { }

@Service
class OrderService {
    @Autowired
    PaymentGateway gateway; // ambiguous! Two candidates — NoUniqueBeanDefinitionException at startup
}

@Primary designates one candidate as the default to use whenever multiple beans of a type match and no more specific instruction is given:

@Component
@Primary
class StripeGateway implements PaymentGateway { } // chosen by default among the candidates

@Qualifier lets a specific injection point name exactly which bean it wants, by bean name (or a custom qualifier value):

@Service
class OrderService {
    private final PaymentGateway gateway;

    OrderService(@Qualifier("payPalGateway") PaymentGateway gateway) {
        this.gateway = gateway; // explicitly requests the PayPal bean, regardless of @Primary
    }
}

Precedence: an explicit @Qualifier at the injection site always wins over @Primary@Primary only matters when the injection point gives no more specific instruction. This lets you set a sensible application-wide default with @Primary while still allowing specific call sites to opt into a different implementation via @Qualifier where needed.

@Qualifier can also be used with a custom annotation (@Qualifier as a meta-annotation on your own annotation type) for more expressive, type-safe disambiguation than raw string bean names.