skip to content

@Qualifier, @Primary & Disambiguation

When more than one bean matches a type, @Primary picks a default and @Qualifier picks by name or by a custom annotation, with bean-name fallback in between. Interviewers reach for this the moment you mention having two implementations of an interface.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What does @Primary do, and when would you reach for it?

level: juniorimportance: must knowfreq 78%

answer

  1. default candidate when several match
  2. definition side, not injection side
  3. only one @Primary per type
  4. @Qualifier overrides @Primary
  5. collections get all, not filtered

basics

~20 s

@Primary marks one bean as the default choice when several beans of the same type exist. If an injection point doesn't say which one it wants, Spring picks the @Primary one instead of throwing an error.

solid answer

~40 s

When two or more beans match a required type, autowiring by type alone is ambiguous and Spring throws NoUniqueBeanDefinitionException. @Primary designates one of those beans as the default candidate, so any unqualified injection point resolves to it. It's ideal when there's an obvious 'main' implementation and one or two special cases: mark the main one @Primary, and let the special cases be selected explicitly with @Qualifier. Only one bean of a given type may be @Primary — two primaries reintroduce ambiguity and fail. @Primary is a hint at the definition side (on the class or @Bean method); it doesn't force anything on injection points that use @Qualifier, which always overrides it. Think of it as 'the winner by default, unless someone asks for a specific one.'

code

java · 21 lines
java
public interface PaymentGateway { void charge(long cents); }

@Service
@Primary
public class StripeGateway implements PaymentGateway {
    public void charge(long cents) { /* ... */ }
}

@Service
public class LegacyGateway implements PaymentGateway {
    public void charge(long cents) { /* ... */ }
}

@Service
public class CheckoutService {
    private final PaymentGateway gateway;
    // No qualifier -> resolves to StripeGateway because it is @Primary
    public CheckoutService(PaymentGateway gateway) {
        this.gateway = gateway;
    }
}

go deeper

for a junior

Must know the one-liner: @Primary = default bean when several match, avoids NoUniqueBeanDefinitionException.

for a middle

Should know it lives on the definition, only one per type, and @Qualifier overrides it.

for a senior

Frames it as a design choice (clear default + explicit exceptions) vs. over-qualifying everything.

for a principal

Contrasts @Primary with @Fallback and discusses library/auto-config ergonomics of defaults.

## The problem @Primary solves Spring's default autowiring is **by type**. When you write `@Autowired PaymentGateway gateway`, Spring looks for exactly one bean assignable to `PaymentGateway`. If it finds **zero**, it fails with `NoSuchBeanDefinitionException`. If it finds **more than one**, it fails with `NoUniqueBeanDefinitionException` — the container can't guess which one you meant. `@Primary` (`org.springframework.context.annotation.Primary`) resolves that ambiguity by nominating **one bean as the default candidate**. When multiple beans match a type and the injection point gives no other hint, the `@Primary` bean is chosen and the others are ignored. ## Where you put it `@Primary` goes on the **bean definition side**, not the injection side: - On a `@Component`/`@Service`/`@Repository` class, or - On a `@Bean` factory method inside a `@Configuration` class. ```java @Service @Primary class StripeGateway implements PaymentGateway { } @Service class LegacyGateway implements PaymentGateway { } ``` Now `@Autowired PaymentGateway gateway` gets `StripeGateway`, no qualifier needed. Code that specifically wants the legacy one uses `@Qualifier("legacyGateway")`. ## Key rules and edge cases - **Only one primary per type.** If two beans of the same type are both `@Primary`, you're back to ambiguity — Spring throws `NoUniqueBeanDefinitionException` ("more than one 'primary' bean found"). - **@Qualifier beats @Primary.** If the injection point has a `@Qualifier`, that narrowing wins; `@Primary` is only the tie-breaker for **unqualified** injection points. - **Scope of the default is the type, not globally.** `@Primary` only affects resolution among beans matching the injected type. - **Collections ignore it.** Injecting `List<PaymentGateway>` gives you *all* matching beans; `@Primary` doesn't filter a collection — it only picks a single winner for a single-value injection. - **@Primary vs @Fallback** (Spring 6.2): `@Primary` says "prefer me"; `@Fallback` says "use me only if nothing else matches." They're logical opposites. ## When to use it Use `@Primary` when there is a clear **default implementation** and other implementations are exceptions. Avoid using it to paper over a genuinely ambiguous design where callers really should be explicit — in that case, qualify every injection point instead. A common real-world case: multiple `DataSource` beans where one is the app's main database (`@Primary`) and others are for reporting/replicas selected by `@Qualifier`.

  • What happens if two beans of the same type are both annotated @Primary?
    Resolution is ambiguous again: Spring throws NoUniqueBeanDefinitionException because it found more than one primary candidate for the type.
  • If an injection point has @Qualifier and another bean is @Primary, which wins?
    @Qualifier wins. @Primary is only the default for injection points that give no other hint; an explicit qualifier always overrides it.

saying these in an interview costs you the question

  • Thinking @Primary is placed on the @Autowired injection point rather than the bean definition
  • Believing you can mark several beans @Primary to 'prioritize' them
  • Assuming @Primary filters a List<T> injection down to one bean

context

open as a page

How does @Qualifier select a specific bean, and what is bean-name fallback matching?

level: middleimportance: must knowfreq 74%

basics

~20 s

@Qualifier("name") tells Spring exactly which bean to inject when several match by type. If no bean carries that qualifier value, Spring falls back to matching the value against bean names — so @Qualifier can also target a bean by its id.

open as a page

How do you create and use a custom qualifier annotation, and why prefer it over @Qualifier("string")?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Define your own annotation meta-annotated with @Qualifier, e.g. @Fast. Put it on the bean and on the injection point. Spring matches them like a typed qualifier. It's refactor-safe and typo-proof, unlike a plain @Qualifier("fast") string.

open as a page

Walk through Spring's full candidate-resolution algorithm when multiple beans match an injection point.

level: seniorimportance: should knowfreq 52%

basics

~20 s

Spring collects all beans of the required type. It filters by @Qualifier, then prefers a @Primary bean, then the highest @Priority, then a bean whose name matches the injection point. If none of those uniquely picks one, it throws NoUniqueBeanDefinitionException.

open as a page

What is @Fallback (Spring 6.2), how does it differ from @Primary, and when would a library use it?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

@Fallback (Spring 6.2) marks a bean as a last-resort candidate: it's used only when no regular bean of that type exists. It's the opposite of @Primary — @Primary says 'prefer me', @Fallback says 'use me only if there's nothing else'.

open as a page