Spring @Primary Annotation

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.