1. 概述
本文中我们将共同学习Spring自3.0版本引入的@Primary注解。
单词Primary意为首要的、主要的,其功能与名称相同:在依赖注入的过程中,当同一类型存在多个bean时,将首要(首先、优先)注入使用@Primary 注解的那个。
2. 适用场景
有些时候我们需要为同一类型注册多个不同的bean。
比如下述代码中我们为类型Employee(员工)提供了两个不同的bean:
@Configuration public class Config { @Bean public Employee❶ JohnEmployee() { return new Employee("John")❷; } @Bean public Employee❶ TonyEmployee() { return new Employee("Tony")❷; } }
- ❶ 类型均为Employee
- ❷ 返回两个不同的bean
然后使用@Autowired进行注入:
@Autowired❶ Employee❷ employee;
- 此时当我们尝试 ❶注入 ❷Employee 时,则将发生NoUniqueBeanDefinitionException异常:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springPrimaryApplication': Unsatisfied dependency expressed through field 'employee'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'club.codedemo.springprimary.Employee' available: expected single matching bean but found 2: JohnEmployee,TonyEmployee Action: Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
我们通常使用@Qualifier(bean的名称) 来指定具体注入哪个bean以规避此类异常。关于@Quailfer的更多用法,请参考本文。
本文我们将重点介绍采用@Primary注解来处理此类问题。
3. @Primary 与 @Bean 结合使用
在注入过程中由于多个bean满足某一类型,同时这些bean之间又没有主次之分,所以Spring无法擅自做主为我们选择注入其中的某一个bean。
@Primary 则会告之Spring哪个bean的地位是主要的、首要的、要优先考虑的,此时当发生类型情况下,Spring在注入时则会优先使用这个主bean。
@Bean @Primary ★ public Employee JohnEmployee() { return new Employee("John"); }
值得注意的是:同类型被声明为Primary的bean最多只能有一个。如果我们在同一类型的Bean上声明多个Primary,同样会发生NoUniqueBeanDefinitionException异常,错误代码示例如下:
@Bean @Primary ✘ public Employee JohnEmployee() { return new Employee("John"); } @Bean @Primary ✘ public Employee TonyEmployee() { return new Employee("Tony"); }
- ✘ 同一Employee类型,在多个Bean中使用了 @Primary注解,将引发NoUniqueBeanDefinitionException异常。
此时Spring在注入时发现了多个被声明为主的bean,两个主bean的优先级相同。Spring同样没有办法自作主张的注入一个其中一个bean给我们,报错信息如下:
more than one 'primary' bean found among candidates: [JohnEmployee, TonyEmployee] 多于一个主bean被找到...
4. @Primary 与 @Component 结合使用
@Primary还可以与@Component注解结合使用。
@Component @Primary public class SmsServiceAliImpl implements SmsService { @Override public void sendMessage(String phone, String message) { } } @Component public class SmsServiceBaiduImpl implements SmsService { @Override public void sendMessage(String phone, String message) { } }
由于@Service、@Controller等注解也属于@Component注解,所以@Primary同样可以与它们结合使用。
@Service @Primary public class FooServiceImpl implements FooService { }
5. 总结
当同一类型存在多个bean时,使用@Primary注解可以轻松的确定一个主bean出来,这为Spring在完成注入时提供了依据。既然被称为主bean,则必须保证其唯一,所以相同类型被@Primary声明的Bean最多只能有一个。
- code demo:
- 参考文章:https://www.baeldung.com/spring-primary