Table of Contents
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.maixuanviet.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.