【问题标题】:How to specify sub-dependency for AutoWired Beans如何为 AutoWired Beans 指定子依赖项
【发布时间】:2019-11-15 13:03:53
【问题描述】:

我有一个这样定义的 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 注释来做同样的事情?

【问题讨论】:

    标签: java spring spring-annotations spring-bean


    【解决方案1】:

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

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

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


    回复您的评论。

    要让将使用 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 类中声明 bean:

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

    SearchIndexImpl bean 现在将通过 IndexUpdater getIndexUpdater() 解决依赖关系。
    这里我们使用@Component 表示一个bean,@Bean 表示它的依赖项。
    但我们也可以通过仅使用 @Bean 并删除 3 个类上的 @Component 来实现对 bean 的完全控制:

    @Configuration
    public class MyConfiguration{
    
    @Bean
    public IndexUpdater getIndexUpdater(){
         return new IndexDirectUpdater();
    }
    
    @Bean 
    public SearchIndexImpl getSearchIndexFoo(){
         return new SearchIndexImpl(getIndexUpdater());
    }
    

    【讨论】:

    • @Qualifier 硬编码IndexUpdater 以供使用。在这种情况下,它将始终是直接更新程序。我希望任何想要使用该类的人来决定使用哪个索引更新器。
    • 你不能,因为 bean 是在 Spring 启动时设置的,并且依赖项不是根据操作它的客户端而设计的。更好的方法是自动装配SearchIndexImpl() 中的两个依赖项,并根据客户端参数使用一个或第二个。其他替代方法:允许客户端在调用 SearchIndexImplBean 上的方法时传递 IndexUpdater 的实例。在某些情况下可能有意义。
    • 我明白了。但在 XML 定义中,可以执行以下操作:``` ``` 有吗没有使用 Java 注释的等价物?
    • 评论中的 XML 不容易阅读,所以我更新了我的问题。
    • 我添加了一些替代方法来设置组件外部的依赖关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多