如何为 AutoWired Bean 指定子依赖

How to specify sub-dependency for AutoWired Beans

我有一个这样定义的 Spring 组件:

@Component
public class SearchIndexImpl implements SearchIndex {
    IndexUpdater indexUpdater;

    @Autowired
    public SearchIndexImpl(final IndexUpdater indexUpdater) {
        Preconditions.checkNotNull(indexUpdater);
        this.indexUpdater = indexUpdater;
    }
}

以及 IndexUpdater 接口的两个实现,例如:

@Component
public class IndexDirectUpdater implements IndexUpdater, DisposableBean, InitializingBean {

}

@Component
public class IndexQueueUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}

如果我尝试像这样自动连接 SearchIndexImpl

@Autowired
private SearchIndex searchIndex;

我得到以下异常:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'IndexUpdater' available: expected single matching bean but found 2: indexDirectUpdater,indexQueueUpdater

这是预料之中的,因为 Spring 无法判断要为 SearchIndexImpl 的构造函数中的 indexUpdater 参数自动连接哪个 IndexUpdater 实现。如何将 Spring 引导至它应该使用的 bean?我知道我可以使用 @Qualifier 注释,但这会将索引更新程序硬编码为实现之一,同时我希望用户能够指定要使用的索引更新程序。在 XML 中,我可以做类似的事情:

<bean id="searchIndexWithDirectUpdater" class="SearchIndexImpl"> 
    <constructor-arg index="0" ref="indexDirectUpdater"/>
</bean>

如何使用 Spring 的 Java 注释来做同样的事情?

使用 @Qualifier 注释指定要使用的依赖项:

public SearchIndexImpl(@Qualifier("indexDirectUpdater") IndexUpdater indexUpdater) {
    Preconditions.checkNotNull(indexUpdater);
    this.indexUpdater = indexUpdater;
}

请注意,自 Spring 4 以来,不需要 @Autowired 来自动装配 bean 的 arg 构造函数。


回复您的评论。

要让 class 将使用 bean 来定义要使用的依赖项,您可以允许它定义要注入容器的 IndexUpdater 实例,例如:

// @Component not required any longer
public class IndexDirectUpdater implements IndexUpdater, DisposableBean, InitializingBean {

}

// @Component not required any longer
public class IndexQueueUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}

在 @Configuration class 中声明 bean:

@Configuration
public class MyConfiguration{

@Bean
public IndexUpdater getIndexUpdater(){
     return new IndexDirectUpdater();
}

由于 IndexUpdater getIndexUpdater()SearchIndexImpl bean 现在将解决依赖关系。
这里我们对一个 bean 使用 @Component,对它的依赖使用 @Bean
但是我们也可以通过仅使用 @Bean 并删除 3 classes 上的 @Component 来允许对要实例化的 bean 进行完全控制:

@Configuration
public class MyConfiguration{

@Bean
public IndexUpdater getIndexUpdater(){
     return new IndexDirectUpdater();
}

@Bean 
public SearchIndexImpl getSearchIndexFoo(){
     return new SearchIndexImpl(getIndexUpdater());
}