Question 27 · Section 5

What to Do If There Are Multiple Beans of the Same Type?

If Spring finds multiple beans of the same type -> error!

Language versions: English Russian Ukrainian

Junior Level

If Spring finds multiple beans of the same type -> error!

Solutions:

1. @Primary - primary bean:

@Primary
@Bean
public PaymentService defaultPayment() { ... }

2. @Qualifier - explicit choice:

@Autowired
@Qualifier("stripePayment")
private PaymentService payment;

3. Variable name:

@Autowired
private PaymentService stripePayment;  // By bean name!

Middle Level

Resolution Order

1. @Qualifier - explicit filter by name (highest priority)
2. @Primary - global "default" marker
3. Variable name (byName) - if no @Qualifier and @Primary
4. @Priority (JSR-250) - numeric priority at class level

Injecting All Beans

// All PaymentService implementations
@Autowired
List<PaymentService> allPayments;

// Map: bean name -> bean
@Autowired
Map<String, PaymentService> paymentMap;

// Usage:
PaymentService service = paymentMap.get("stripe");

ObjectProvider

@Autowired
ObjectProvider<PaymentService> provider;

PaymentService service = provider.getIfAvailable(
    () -> new DefaultPaymentService()  // Fallback!
);

Senior Level

Custom Qualifiers

@Qualifier
@Retention(RUNTIME)
public @interface StripePayment { }

@StripePayment
@Bean
public PaymentService stripePayment() { ... }

@Autowired
@StripePayment
private PaymentService payment;

// -> Type-safe, no typos!

NoUniqueBeanDefinitionException Diagnostics

// Spring Boot FailureAnalyzer automatically shows all found beans
// on NoUniqueBeanDefinitionException - no need to dig into stack trace.

Production Experience

Real scenario: 10 implementations

Strategy pattern:
  -> Map<String, Strategy> strategies
  -> Selection by key at runtime
  -> Without if/else!

Best Practices

  1. @Primary -> one primary bean
  2. @Qualifier -> explicit choice
  3. Map -> Strategy pattern
  4. Custom qualifiers -> type-safe
  5. ObjectProvider -> fallback
  6. @ConditionalOnMissingBean -> in starters

Summary for Senior

  • @Primary -> default bean
  • @Qualifier -> precise choice
  • Map -> all beans, selection by key
  • Custom qualifiers -> type-safe
  • ObjectProvider -> lazy + fallback
  • FailureAnalyzer -> error diagnostics

Interview Cheat Sheet

Must know:

  • Resolution order: @Qualifier -> @Primary -> byName -> @Priority (JSR-250)
  • @Primary - global “default bean” marker for a given type
  • @Qualifier - explicit filter by name, highest priority
  • Inject all beans: List (order) or Map<String, T> (name -> bean) - Strategy pattern
  • ObjectProvider.getIfAvailable(fallback) - lazy retrieval with fallback
  • Custom qualifiers (@Qualifier + meta-annotation) - type-safe, no strings
  • Spring Boot FailureAnalyzer automatically shows all found beans on NoUniqueBeanDefinitionException

Common follow-up questions:

  • What has priority: @Primary or @Qualifier? - @Qualifier, explicit choice always takes priority.
  • How to implement Strategy pattern in Spring? - Map<String, Strategy> - key = bean name, selection at runtime without if/else.
  • What happens if there is no @Primary, no @Qualifier, and no name match? - NoUniqueBeanDefinitionException.
  • Why are custom qualifiers needed? - Type safety: compiler catches errors, no typos in strings.

Red flags (DO NOT say):

  • “@Primary always overrides @Qualifier” - no, @Qualifier has highest priority.
  • “Map injects only one bean” - no, Map contains ALL beans of the type, key = name.
  • “It is fine to use strings in @Qualifier” - risky: typos caught only at runtime.
  • “If there is @Primary, no other beans of this type exist” - no, all beans are registered, @Primary only selects default.

Related topics:

  • [[28. What is Qualifier]]
  • [[26. What does the Autowired annotation do]]
  • [[24. What is a Configuration class]]
  • [[25. Difference between Component Service Repository Controller]]