分类
spring

Spring @Primary 注解介绍

Spring @Primary Annotation

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最多只能有一个。