Java 春季@Qualifier的优势是什么?

Java 春季@Qualifier的优势是什么?,java,spring,spring-boot,Java,Spring,Spring Boot,假设我们有两种接口实现: @组件 公共级丰田汽车{} @组成部分 公共级宝马汽车{} 使用@限定符 @Autowired @限定词(“丰田”) 私家车; 自动布线时是否过度使用特定的实现类型 @Autowired 丰田私家车; 我在这里看到的@Qualifier的缺点是依赖一个可能与bean(类)名称不同步的字符串,从而失去了“类型安全性” 如何避免这种脆弱性?@Qualifier的优点是什么?除了@Component之外,还有其他创建bean的方法。考虑: @Configuration

假设我们有两种接口实现:

@组件
公共级丰田汽车{}
@组成部分
公共级宝马汽车{}
使用
@限定符

@Autowired
@限定词(“丰田”)
私家车;
自动布线时是否过度使用特定的实现类型

@Autowired
丰田私家车;
我在这里看到的
@Qualifier
的缺点是依赖一个可能与bean(类)名称不同步的字符串,从而失去了“类型安全性”


如何避免这种脆弱性?
@Qualifier
的优点是什么?

除了
@Component
之外,还有其他创建bean的方法。考虑:

@Configuration
public class CarConfig {
    @Bean
    public Toyota first() {
        return new Toyota(1);
    }

    @Bean
    public Toyota second() {
        return new Toyota(2);
    }
}
在本例中,您的第二个示例不可能通过选择更具体的类型来消除歧义。使用命名限定符是在这两者之间进行选择的唯一方法


您也可能不想让客户机类知道接口的具体实现。它可能会鼓励客户机类使用丰田API中不属于Car接口的方法。依赖这些方法将增加耦合,并可能使以后更难将实现换成不同的实现。

以下方法如何:

public final class CarTypes {
    private CarTypes() {}
    public static final String TOYOTA = “toyota”;
    public static final String BMW = “bmw”;
}
以及弹簧配置:

static import CarTypes.*;
@Configuration
public class MyConfig {

   @Bean(name = TOYOTA)
   public Car toyotaWhateverMethod() { return new Toyota();}
    @Bean(name = BMW) 
    public Car bmwWhateverMethod() {return new BMW();}
    @Bean
    public CarFactory toyotaCarFactory(@Qualifier(TOYOTA) Car car) {
        return new CarFactory(car); 
    } 
          
}

请注意,类本身根本不携带任何注释,在配置中,您始终依赖于静态导入的类的最终字段
CarTypes

,它允许您编程到接口,而不是实现。请参阅编程到接口的好处

因此,如果您编程到一个接口,您应该自动连接到一个接口而不是一个实现,并且
@Qualifier
用于指定如果您有多个bean实现同一接口,那么要注入哪个bean

我看到,由于依赖一个字符串,它正在失去“类型安全性” 与bean(类)名称不同步。如何避免这种情况 脆弱性

您只需在
@Component
中显式地配置bean名称,而不依赖于从类名派生bean名称的默认值。为bean名称设置一个常量,并确保需要访问它的所有代码都应该通过该常量访问:

@组件(Toyota.BEAN\u名称)
公共级丰田汽车{
公共静态最终字符串BEAN\u NAME=“MyToyota”;
}
@Autowired
@限定符(Toyota.BEAN\u名称)
私家车;

与编写接口时一样:从实现中抽象。通过指定
@Qualifier(“丰田”)
,您指明了特定的需求,但仍然没有指定应该如何实现。通过SpringBoot的自动配置特性,可以有许多使用该限定符的实现类,然后自动配置可以选择一个要加载的类。如果你硬链接到一个类,你不能这样做。不要使用字段注入。Spring团队建议构造函数注入。@Michael,我同意,现场注入只是为了简洁起见example@Andreas您能提供一个自动配置的代码示例,用相同的限定符选择其中一个实现吗?我实际上从来没有见过“真正的”这个例子会让我相信
@Qualifier
是一件好事,我看到的所有示例都是从Spring注入开始的。我想我还没见过。我喜欢你的问题,以及如何避免字符串文字的脆弱性,它的值仍然是实现类名?因为它是类名,所以耦合仍然在源代码中;如果实现类名更改,编译不会显示,只有
BeanInstantiationException
会在运行时显示它。@Hawk运行时DI总是会有一些脆弱性。您的设置也不能免受运行时问题的影响-如果Toyota不是一个bean,例如,如果它没有用
@组件
注释,该怎么办?它在运行时也会失败。有时我增加自信的方法是通过一个
@SpringBootTest
单元测试,它不断言任何东西,它只是启动应用程序并确保组件正确连接在一起。基本上是烟雾测试。这些天来,我逐渐远离Spring,转而支持在编译时执行DI工作的框架,比如Micronaut,但是在实现中保持常量不是一个好主意-您仍然要与实现耦合。如果您希望与实现100%解耦,没有人阻止您在接口中声明该常量。我只是告诉你这个主意
static import CarTypes.*;
@Configuration
public class MyConfig {

   @Bean(name = TOYOTA)
   public Car toyotaWhateverMethod() { return new Toyota();}
    @Bean(name = BMW) 
    public Car bmwWhateverMethod() {return new BMW();}
    @Bean
    public CarFactory toyotaCarFactory(@Qualifier(TOYOTA) Car car) {
        return new CarFactory(car); 
    } 
          
}