我有一个奇怪的情况。我正在尝试编写自动配置类,如果另一个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'
答案 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
}