1. Overview
In this quick tutorial, we’ll discuss Spring’s @Primary annotation which was introduced with version 3.0 of the framework.
Simply put, we use @Primary to give higher preference to a bean when there are multiple beans of the same type.
Let’s describe the problem in detail.
2. Why Is @Primary Needed?
In some cases, we need to register more than one bean of the same type.
In this example we have JohnEmployee() and TonyEmployee() beans of the Employee type:
@Configuration
public class Config {
@Bean
public Employee JohnEmployee() {
return new Employee("John");
}
@Bean
public Employee TonyEmployee() {
return new Employee("Tony");
}
}
Spring throws NoUniqueBeanDefinitionException if we try to run the application.
To access beans with the same type we usually use @Qualifier(“beanName”) annotation.
We apply it at the injection point along with @Autowired. In our case, we select the beans at the configuration phase so @Qualifier can’t be applied here. We can learn more about @Qualifier annotation by following the link.
To resolve this issue Spring offers the @Primary annotation.
3. Use @Primary With @Bean
Let’s have a look at configuration class:
@Configuration
public class Config {
@Bean
public Employee JohnEmployee() {
return new Employee("John");
}
@Bean
@Primary
public Employee TonyEmployee() {
return new Employee("Tony");
}
}
*We mark TonyEmployee() bean with @Primary. Spring will inject TonyEmployee() bean preferentially over the JohnEmployee().*
Now, let’s start the application context and get the Employee bean from it:
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(Config.class);
Employee employee = context.getBean(Employee.class);
System.out.println(employee);
After we run the application:
Employee{name='Tony'}
From the output, we can see that the TonyEmployee() instance has a preference while autowiring.
4. Use @Primary With @Component
We can use @Primary directly on the beans. Let’s have a look at the following scenario:
public interface Manager {
String getManagerName();
}
We have a Manager interface and two subclass beans, DepartmentManager:
@Component
public class DepartmentManager implements Manager {
@Override
public String getManagerName() {
return "Department manager";
}
}
And the GeneralManager bean:
@Component
@Primary
public class GeneralManager implements Manager {
@Override
public String getManagerName() {
return "General manager";
}
}
They both override the getManagerName() of the Manager interface. Also, note that we mark the GeneralManager bean with @Primary.
This time, @Primary only makes sense when we enable the component scan:
@Configuration
@ComponentScan(basePackages="org.baeldung.primary")
public class Config {
}
Let’s create a service to use dependency injection while finding the right bean:
@Service
public class ManagerService {
@Autowired
private Manager manager;
public Manager getManager() {
return manager;
}
}
Here, both beans DepartmentManager and GeneralManager are eligible for autowiring.
As we marked GeneralManager bean with @Primary, it will be selected for dependency injection:
ManagerService service = context.getBean(ManagerService.class);
Manager manager = service.getManager();
System.out.println(manager.getManagerName());
The output is “General manager”.
5. Conclusion
In this article, we learned about Spring’s @Primary annotation. With the code examples, we demonstrated the need and the use cases of the @Primary.
As usual, the complete code for this article is available over on GitHub project.