首页 > 解决方案 > @ConditionalOnMissingBean 和 @ConditionalOnBean 在同一类型上

问题描述

我遇到了奇怪的情况。我正在尝试编写自动配置类,如果另一个 bean 存在或不存在,我将在其中创建 bean,所以我有条件 bean 和条件相同类型的缺少 bean..

这是我的代码:

@Bean
@ConditionalOnMissingBean(
    type = {"com.example.Api"}
)
public ApiManager apiManager() {
    return new ApiManager() {
        public Result getValue(Request request) {
            throw new Exception("Api not provided.");
        }

        public Result setValue(Request request) {
            throw new Exception("Api not provided.");
        }
    };
}

@Bean
@ConditionalOnBean(
    type = {"com.example.Api"}
)
public ApiManager apiManager(Api api) {
    return new ApiManagerImpl(api);
}

问题是它不检查@ConditionalOnBean它是否已经签入@ConditionalOnMissingBean该类型com.example.Api的 bean 没有丢失,然后没有创建 bean。

我得到如下错误:

Parameter 2 of constructor in com.example.ServiceImpl required a bean of type 'com.example.ApiManager' that could not be found.
- Bean method 'apiManager' in 'ApiAutoConfiguration' not loaded because @ConditionalOnMissingBean (types: com.example.Api; SearchStrategy: all) found bean 'api'
- Bean method 'apiManager' in 'ApiAutoConfiguration' not loaded because @ConditionalOnMissingBean (types: com.example.Api; SearchStrategy: all) found bean 'api'

标签: javaspringspring-boot

解决方案


你得到的东西是非常合乎逻辑的。条件是按顺序评估的,这就是在用户配置之后处理自动配置的原因。

如果上下文符合您的预期,我们必须在执行任何操作之前评估所有 bean 定义的所有条件。这将破坏自动配置处理用户(用户配置)或自动配置提供某种类型的bean这一事实的目的。

您需要重写此自动配置以按顺序导入内容。一种方法是移动包私有配置类上的每个方法,然后执行以下操作:

@Configuration
@Import({ApiPresentConfiguration.class, ApiNotPresentConfiguration.class})

真正处理这个问题的更好方法是根本不这样做,只需使用ObjectProvider

@Bean
public ApiManager apiManager(ObjectProvider<Api> api) {
    // Check if API is present and then return the appropriate implementation
}

推荐阅读