
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: May 11, 2024
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.
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.
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.
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”.
In addition, when using the @Primary annotation, it’s important to ensure that each bean name is unique within the context. Spring uses the method name as the default bean name. While @Primary indicates which bean should be injected by default in case of ambiguity, it doesn’t allow multiple beans with the same name in the same configuration class.
To avoid such conflicts, we need to make sure each method in a configuration class has a unique name. Moreover, we can explicitly specify the name directly in the @Bean annotation using the name attribute:
@Bean(name = "mercedesCar")
public Car car1() {
return new Car("Mercedes");
}
@Bean(name = "bmwCar")
@Primary
public Car car2() {
return new Car("BMW");
}
In this case, the beans are named mercedesCar and bmwCar, ensuring uniqueness and avoiding conflicts.
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.
Follow the Spring Category