0
0
SpringbootComparisonBeginner · 4 min read

@Qualifier vs @Primary: Key Differences and Usage in Spring

In Spring, @Primary marks a single bean as the default choice when multiple beans of the same type exist, while @Qualifier explicitly specifies which bean to inject by name. Use @Primary for a general default and @Qualifier for precise selection among multiple candidates.
⚖️

Quick Comparison

This table summarizes the main differences between @Qualifier and @Primary annotations in Spring.

Aspect@Primary@Qualifier
PurposeMarks a bean as the default when multiple beans existSpecifies exactly which bean to inject by name
Number of BeansOnly one bean should be marked as primary per typeCan be used on multiple beans with different names
Usage LocationPlaced on bean definitionUsed on injection point or bean definition
ResolutionSpring injects primary bean automatically if no qualifierSpring injects bean matching qualifier explicitly
FlexibilityLess flexible, one default per typeMore flexible, can select any bean explicitly
Typical Use CaseSet a common default beanChoose specific bean when multiple exist
⚖️

Key Differences

@Primary is used to mark one bean as the default choice when Spring finds multiple beans of the same type during dependency injection. If no other hints are given, Spring injects the @Primary bean automatically. This helps avoid ambiguity without specifying bean names everywhere.

On the other hand, @Qualifier is used to explicitly specify which bean to inject by its name or qualifier value. It can be placed on the injection point or on the bean definition itself. This is useful when you want to select a specific bean among many, overriding the default @Primary if present.

In summary, @Primary provides a default fallback bean, while @Qualifier gives precise control over which bean is injected. They can be used together: @Primary sets the default, and @Qualifier overrides it when needed.

⚖️

Code Comparison

Example showing how @Primary works to select the default bean automatically.

java
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

interface GreetingService {
    String greet();
}

@Component
@Primary
class EnglishGreetingService implements GreetingService {
    public String greet() {
        return "Hello!";
    }
}

@Component
class SpanishGreetingService implements GreetingService {
    public String greet() {
        return "¡Hola!";
    }
}

@Service
class GreetingClient {
    private final GreetingService greetingService;

    @Autowired
    public GreetingClient(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    public String sayGreeting() {
        return greetingService.greet();
    }
}

// When GreetingClient is used, EnglishGreetingService is injected by default because of @Primary.
Output
Hello!
↔️

@Qualifier Equivalent

Example showing how @Qualifier explicitly selects the bean to inject by name, overriding any @Primary.

java
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

interface GreetingService {
    String greet();
}

@Component("englishService")
class EnglishGreetingService implements GreetingService {
    public String greet() {
        return "Hello!";
    }
}

@Component("spanishService")
class SpanishGreetingService implements GreetingService {
    public String greet() {
        return "¡Hola!";
    }
}

@Service
class GreetingClient {
    private final GreetingService greetingService;

    @Autowired
    public GreetingClient(@Qualifier("spanishService") GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    public String sayGreeting() {
        return greetingService.greet();
    }
}

// GreetingClient injects SpanishGreetingService explicitly using @Qualifier("spanishService").
Output
¡Hola!
🎯

When to Use Which

Choose @Primary when you have one main bean implementation that should be the default for injection in most cases. It reduces the need to specify bean names everywhere and keeps code cleaner.

Choose @Qualifier when you need to inject a specific bean among multiple candidates, especially when the default @Primary bean is not suitable. It gives precise control and avoids ambiguity explicitly.

In practice, use @Primary to set a sensible default and @Qualifier to override that default in special cases.

Key Takeaways

@Primary sets a default bean for injection when multiple beans exist.
@Qualifier explicitly selects which bean to inject by name or qualifier.
Use @Primary for general default and @Qualifier for specific cases.
They can be combined: @Primary provides fallback, @Qualifier overrides it.
Choosing the right annotation improves clarity and avoids injection conflicts.