@ConditionalOnMissingBean和@ConditionalOnBean在相同类型上

时间:2019-04-09 13:56:09

标签: java spring spring-boot

我有一个奇怪的情况。我正在尝试编写自动配置类,如果另一个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类型的bean没有丢失并且没有创建bean,它就不会检查com.example.Api

我收到如下错误:

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'

1 个答案:

答案 0 :(得分:2)

您得到的是很合逻辑的。条件按顺序进行评估,这就是为什么在用户配置之后处理自动配置的原因。

如果上下文符合您的期望,则在执行任何操作之前,我们必须评估所有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
}