Learnitweb

Spring @Primary annotation

1. Introduction

In this quick tutorial, we’ll discuss Spring’s @Primary annotation.

The @Primary annotation indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If there is exactly one bean annotated with @Primary among the candidates, it will be used for autowiring.

This annotation may be used on any class directly or indirectly annotated with @Component or on methods annotated with @Bean. Since @Repository, @Service and @Controller serve as specialization of @Component, it can be used with these annotations.

2. What problem does @Primary solve?

While autowiring beans, it is possible that there are more than one eligible candidates. While autowiring beans, Spring by default searches by types and does the bean injection. There will be ambiguity when two or more beans are registered of the same type. Let’s understand this with an example.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@RestController
public class HelloController {
@Autowired
Printable printer;
@GetMapping("/print")
public void print() {
printer.print();
}
}
@RestController public class HelloController { @Autowired Printable printer; @GetMapping("/print") public void print() { printer.print(); } }
@RestController
public class HelloController {

  @Autowired
  Printable printer;

  @GetMapping("/print")
  public void print() {
    printer.print();
  }
} 
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// imports omitted for brevity
@Service("filePrinter")
public class FilePrinter implements Printable {
@Override
public void print() {
System.out.println("file printer");
}
}
// imports omitted for brevity @Service("filePrinter") public class FilePrinter implements Printable { @Override public void print() { System.out.println("file printer"); } }
// imports omitted for brevity

@Service("filePrinter")
public class FilePrinter implements Printable {

  @Override
  public void print() {
    System.out.println("file printer");
  }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// imports omitted for brevity
@Service("screenPrinter")
public class ScreenPrinter implements Printable {
@Override
public void print() {
System.out.println("Screen Printer");
}
}
// imports omitted for brevity @Service("screenPrinter") public class ScreenPrinter implements Printable { @Override public void print() { System.out.println("Screen Printer"); } }
// imports omitted for brevity

@Service("screenPrinter")
public class ScreenPrinter implements Printable {

  @Override
  public void print() {
    System.out.println("Screen Printer");
  }
}

Spring throws NoUniqueBeanDefinitionException if we try to run the application with autowiring two or more beans of same type. In Spring Boot application the exception looks like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Field printer in com.learnitweb.demo.controller.HelloController required a single bean, but 2 were found
Field printer in com.learnitweb.demo.controller.HelloController required a single bean, but 2 were found
Field printer in com.learnitweb.demo.controller.HelloController required a single bean, but 2 were found

3. @Primary annotation

Lets see how the @Primary annotation solves the issue in our example.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Service("screenPrinter")
@Primary
public class ScreenPrinter implements Printable {
@Override
public void print() {
System.out.println("Screen Printer");
}
}
@Service("screenPrinter") @Primary public class ScreenPrinter implements Printable { @Override public void print() { System.out.println("Screen Printer"); } }
@Service("screenPrinter")
@Primary
public class ScreenPrinter implements Printable {

  @Override
  public void print() {
    System.out.println("Screen Printer");
  }
}

Using @Primary annotation will let the Spring to know that ScreenPrinter should be given preference in case of ambiguity. Since two Printable beans are candidates for autowiring, ScreenPrinter will be given preference and will be used for autowiring.

4. Use @Primary With @Bean

The @Primary annotation can be used with @Bean to define the bean as ‘primary’ in case of ambiguity.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Configuration
public class Config {
@Bean
public Printable ScreenPrinter() {
return new ScreenPrinter();
}
@Bean
@Primary
public Printable FilePrinter() {
return new FilePrinter();
}
}
@Configuration public class Config { @Bean public Printable ScreenPrinter() { return new ScreenPrinter(); } @Bean @Primary public Printable FilePrinter() { return new FilePrinter(); } }
@Configuration
public class Config {

    @Bean
    public Printable ScreenPrinter() {
        return new ScreenPrinter();
    }

    @Bean
    @Primary
    public Printable FilePrinter() {
        return new FilePrinter();
    }
}

In this example, FilePrinter is given preference and used in case of ambiguity.