原文链接: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.
和我在这里来讨论下Spring3.0引入的@Primary注解吧。
Simply put, we use @Primary to give higher preference to a bean when there are multiple beans of the same type.
简单来说,使用@Primary注解可以给某个bean对象更高的引用优先级,这个特性,在程序上下文中存在同一类型多个实现时很有效用。
Let's describe the problem in detail. 接下来来详细看一下如何使用吧。
2. Why Is @Primary Needed? 为什么需要这个@Primary注解呢?
In some cases, we need to register more than one bean of the same type.
在某些场景下,我们需要在程序上下文中注册某一接口的多个实现bean对象。
In this example we have JohnEmployee() and TonyEmployee() beans of the Employee type:
在下面的示例中,创建了Employee类型的两个实现bean对象,如下:
@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.
如果直接运行程序,Spring框架会抛出一个 NoUniqueBeanDefinitionException 异常。
To access beans with the same type we usually use @Qualifier(“beanName”) annotation.
在之前的解决方案中,我们一般使用@Qualifier并指定bean名称来解决这个问题。
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.
之前的文章中,@Qualifier注解,是在注入依赖时,搭配@Autowired注解来使用的,而且前提是,多个bean对象,使用了@Component注解来标记了每个bean对象的名称。在这里的示例里,使用了@Bean注解来创建对象,是配置和加载阶段抛出异常的,所以@Qualifier注解在这里不适用。想要了解@Qualifier更多的用法,可以看这里 Guide to Spring @Autowired。
To resolve this issue Spring offers the @Primary annotation.
为了解决这个问题,@Primary注解应运而生,横空出世。
3. Use @Primary With @Bean 和@Bean注解一直使用@Primary注解
Let's have a look at configuration class: 在上面的示例代码中添加@Primary注解,如下:
@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().
这里,使用@Primary注解标记了TonyEmployee,所以Spring框架会更倾向于使用TonyEmployee来注入依赖,而不是JohnEmployee
Now, let's start the application context and get the Employee bean from it:
接下来,看一下上下文中的情况,并获取Employee接口的实现对象,如下:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); Employee employee = context.getBean(Employee.class); System.out.println(employee);
After we run the application: 结果如下,获取到的是Tony
Employee{name='Tony'}
From the output, we can see that the TonyEmployee() instance has a preference while autowiring.
从这个输出结果来看,在自动注入依赖的过程中,使用了@Primary注解标记的Tony更被Spring框架所偏好。
4. Use @Primary With @Component 和@Component注解一直使用
We can use @Primary directly on the beans. Let's have a look at the following scenario:
可以与@Bean注解一直使用@Primary注解,也可以有其它使用场景,来看另一示例:
public interface Manager {
String getManagerName();
}
We have a Manager interface and two subclass beans, DepartmentManager:
下面定义了Manager接口的两个子类对象,一个是DepartManager对象
@Component
public class DepartmentManager implements Manager {
@Override
public String getManagerName() {
return "Department manager";
}
}
And the GeneralManager bean:
另一个是GeneralManager对象
@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.
这两个子类都重载了Manager接口的getManagerName()方法,也请注意,在GeneralManager的类上使用了@Primary注解。
This time, @Primary only makes sense when we enable the component scan:
在这个场景里,@Primary注解只会在我们使用了@ComponentScan注解时才合理有效 ,如下:
@Configuration
@ComponentScan(basePackages="org.baeldung.primary")
public class Config {
}
Let's create a service to use dependency injection while finding the right bean:
创建一个Service来使用Manager接口,Spring会注入它的实现bean,看它是如何找到正确的bean对象,如下:
@Service
public class ManagerService {
@Autowired
private Manager manager;
public Manager getManager() {
return manager;
}
}
Here, both beans DepartmentManager and GeneralManager are eligible for autowiring.
上面的代码中,DepartmentManager和GeneralManager在自动注入阶段,查找Manager接口实现对象时都是对Spring可见的。
As we marked GeneralManager bean with @Primary, it will be selected for dependency injection:
因为我们使用了@Primary注解标记了GeneralManager子类,所以它的bean对象会被用来当作依赖注入
ManagerService service = context.getBean(ManagerService.class); Manager manager = service.getManager(); System.out.println(manager.getManagerName());
The output is “General manager”. 看输出结果,也是期待的结果要,即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.
这篇文章中,了解了@Primary注解,以及它的产生原因、使用场景、工作方式和使用示例。
大家多多点赞关注哈



