Understanding @Primary in Spring

Author:

If you read my post about the @Qualifier annotation, you have noticed that defining two beans of the same type can be a challenge. By distinguishing it with a qualifier name, @Qualifier helps Spring determine which bean to inject.

The @Primary annotation will help Spring decide which of those same types of beans it should pick primarily.

For the bean annotated with the @Primary annotation, the @Qualifier will not be necessary. It is only required for the other bean.

Example 1: Using @Primary and @Qualifier in Spring

Let’s see the example in practice:

public interface GreetingService {
    String greet();
}

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

@Service("spanishGreetingService")
public class SpanishGreetingService implements GreetingService {
    @Override
    public String greet() {
        return "Hola!";
    }
}

@RestController
@RequestMapping("/greet")
public class GreetingController {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GreetingController.class);
    
    @Autowired
    private GreetingService greetingService; 
    
    @Autowired
    @Qualifier("spanishGreetingService")
    private GreetingService spanishGreetingService; 

    @GetMapping
    public ResponseEntity<String> printGreetings() {
        log.info(greetingService.greet()); 
        log.info(spanishGreetingService.greet()); 
        return ResponseEntity.ok("greetings");
    }
}

You won’t need to use the @Qualifier on the bean you defined as @Primary

When you call this controller with this curl:

curl <http://localhost:8080/greet>

You are going to see in the logs that the primary one was automatically set:

2024-06-20T21:08:53.884-03:00  INFO 1868 --- [nio-8080-exec-1] c.s.mastery.primary.GreetingController   : Hello!
2024-06-20T21:08:53.884-03:00  INFO 1868 --- [nio-8080-exec-1] c.s.mastery.primary.GreetingController   : Hola!


Example 2: Using @Primary at the Configuration Level

Another example is when you need to use the bean at the configuration level, so it will not be possible to use the @Qualifier to identify which bean Spring should inject.

@Configuration
public class AppPrimaryConfig {
    @Bean
    @Primary
    public ConfigGreetingService portugueseGreetings() {
        return new PortugueseGreetings();
    }

    @Bean("italianGreetings")
    public ConfigGreetingService italianGreetings() {
        return new ItalianGreetings();
    }

}

@RestController
@RequestMapping("/new-greetings")
public class NewGreetingController {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GreetingController.class);
    @Autowired
    private ConfigGreetingService greetingService;

    @Autowired
    @Qualifier("italianGreetings")
    private ConfigGreetingService italianGreetings;

    @GetMapping
    public ResponseEntity<String> printGreetings() {
        log.info(greetingService.greet());
        log.info(italianGreetings.greet());
        return ResponseEntity.ok("greetings");
    }
}


When you call the controller:

curl <http://localhost:8080/new-greetings>

You should see:

2024-06-20T21:10:17.517-03:00  INFO 8768 --- [nio-8080-exec-1] c.s.mastery.primary.GreetingController   : Ola
2024-06-20T21:10:17.517-03:00  INFO 8768 --- [nio-8080-exec-1] c.s.mastery.primary.GreetingController   : Ciao

Conclusion

In this blog post, you learned about the @Primary annotation and its use cases.

If you like this topic, make sure to follow me. In the following days, I’ll be explaining more about Spring annotations! Stay tuned!

Willian Moya (@WillianFMoya) / X (twitter.com)

Willian Ferreira Moya | LinkedIn

Leave a Reply

Your email address will not be published. Required fields are marked *