SpringPrimary注解

2023/10/23

# 1 @Primary注解

@Primary 注解是 Spring 框架中的一个注解,它用于标识一个 bean 是首选的,当容器中存在多个相同类型的 bean 时,Spring 会优先选择使用 @Primary 标记的 bean。

以下是 @Primary 注解的一些详细说明:

  1. 解决依赖注入歧义性: 当你在 Spring 容器中有多个同一类型的 bean,且不确定应该注入哪一个时,使用 @Primary 可以解决这种歧义性。Spring 容器将优先选择标记为 @Primary 的 bean 进行注入。
  2. 适用于构造函数注入、Setter 方法注入、字段注入等: @Primary 可以用于不同的依赖注入方式,包括构造函数注入、Setter 方法注入以及字段注入。
  3. @Qualifier一起使用: 如果在容器中有多个相同类型的 bean,而你仍需要选择性地注入非首选的 bean,你可以结合使用 @Primary@Qualifier 注解。@Qualifier 允许你指定要注入哪个具体的 bean。
  4. 适用于多个配置文件: 如果你的应用有多个配置文件,每个配置文件定义了相同类型的 bean,你可以在不同的配置文件中使用 @Primary 标记不同的 bean,以确定哪个是首选的。
  5. 不是强制性的: 使用 @Primary 是可选的,如果没有标记任何 bean 为首选,Spring 将会抛出 NoUniqueBeanDefinitionException 异常,表示依赖注入存在歧义。

以下是一个示例,说明如何在 Spring 中使用 @Primary 注解:

@Component
@Primary
public class MyPrimaryBean implements MyInterface {
    // ...
}

@Component
public class MySecondaryBean implements MyInterface {
    // ...
}

@Service
public class MyService {
    private MyInterface myInterface;

    @Autowired
    public MyService(MyInterface myInterface) {
        this.myInterface = myInterface;
    }

    // ...
}

在这个示例中,MyPrimaryBean 被标记为首选 bean,所以当 MyService 类注入 MyInterface 时,MyPrimaryBean 将会被注入。如果没有使用 @Primary,并且存在多个实现了 MyInterface 的 bean,Spring 将无法决定注入哪一个,从而引发异常。

总之,@Primary 注解是 Spring 框架中用于解决依赖注入歧义性的有用工具,可以确保容器在有多个相同类型的 bean 时能够正确地选择要注入的 bean。

# 2 如果primary无法注入到bean

会抛出 NoUniqueBeanDefinitionException 异常,指示依赖注入存在歧义,容器无法确定应该注入哪个 bean。

# 3 primary失败时自动找其他bean

如果你在 Spring 中使用 @Autowired(required = false) 或者 Optional 来处理 @Primary bean 无法注入的情况,那么在没有其他同类型的 bean 时,myInterface 将会保持为 null 或是一个空的 Optional。Spring 不会自动尝试注入其他同类型的 bean,因此不会将 MySecondaryBean 或其他同类型的 bean 注入.

but

如果你希望在 @Primary bean 无法注入时,自动尝试注入其他同类型的 bean,你需要编写自定义逻辑来处理这种情况。这通常涉及编写条件逻辑,以检查是否 myInterfacenull,然后手动尝试注入其他 bean,或者根据应用逻辑选择要注入的具体 bean。这不是 Spring 默认的行为,需要自己编码来实现。

举个示例,以下是一个可能的解决方案:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;

@Service
public class MyService {
    private MyInterface myInterface;

    @Autowired(required = false)
    public void setMyInterface(MyInterface myInterface) {
        this.myInterface = myInterface;
    }

    @Autowired
    private List<MyInterface> allMyInterfaces;

    @PostConstruct
    public void initialize() {
        if (myInterface == null && !allMyInterfaces.isEmpty()) {
            // 在这里根据你的逻辑选择一个具体的备选 bean
            // 这里示例中,遍历所有备选 bean 并选择第一个非空的 bean
            for (MyInterface candidate : allMyInterfaces) {
                if (candidate != null) {
                    myInterface = candidate;
                    break;
                }
            }

            if (myInterface == null) {
                throw new RuntimeException("No suitable bean found for MyInterface.");
            }
        }
    }

    // ...
}