春季以合格的豆为条件

时间:2020-03-13 14:57:28

标签: java spring dependency-injection

在春季如何将@ConditionalOnBean与预选赛一起使用?

下面是独立的示例场景:我有

  • 服务接口SomeService
  • 适配器接口SomeAdapter
  • GreenService的{​​{1}}实现与限定符SomeService,取决于@Green和限定符SomeAdapter
  • @Green的{​​{1}}实现与限定符BlueService,取决于SomeService和限定符@Blue
  • 带有限定符SomeAdapter的{​​{1}}的可选@Blue实现
  • 带有限定符GreenAdapter的{​​{1}}的可选SomeAdapter实现

@绿色预选赛:

@Green

@Blue限定词:

BlueAdapter

GreenService:

SomeAdapter

BlueService:

@Blue

GreenAdapter:

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Green { }

BlueAdapter:

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Blue {  }

测试以检查Bean的激活情况(不包含@Green @Service @ConditionalOnBean(value = SomeAdapter.class, annotation = Green.class) public class GreenService implements SomeService { @Autowired @Green private SomeAdapter adapter; } ,因此@Blue @Service @ConditionalOnBean(value = SomeAdapter.class, annotation = Blue.class) public class BlueService implements SomeService { @Autowired @Blue private SomeAdapter adapter; } 不会处于活动状态):

@Green
@Component
public class GreenAdapter implements SomeAdapter {}

问题:测试无法运行,报告缺少依赖性@Blue @Component public class BlueAdapter implements SomeAdapter {} BlueAdapter中带有限定符BlueService) 。 @RunWith(SpringRunner.class) @ContextConfiguration(classes = {GreenService.class, BlueService.class, GreenAdapter.class}) public class GreenBlueServiceTest { @Autowired @Green private Optional<SomeService> greenService; @Autowired @Blue private Optional<SomeService> blueService; @Test public void testGreen() { assertTrue(greenService.isPresent()); } @Test public void testBlue() { assertFalse(blueService.isPresent()); } } 应该禁用Bean,因为没有SomeAdapter带有限定符@Blue,但这是行不通的。

我发现,当我向BlueService添加@ConditionalOnBean注释(与SomeAdapter相同,但未标记为@Blue)时,将该注释用于bean在@TrueBlue上激活,就像应该做的一样(测试所有绿色)。

结论:

  • 带有必需注释的条件Bean激活有效(原则上)
  • 但是,当必需的注释是@Blue
  • 时,它不起作用

这是错误还是按设计,并且如何实现这种条件激活取决于Spring中合格的bean


编辑:@ bruno-leite的答案解释了为什么它不起作用(注释和bean类型可以在不同的bean上匹配),但是剩下的问题是:

如果存在另一个给定类型和给定注释(或特定限定词)的bean,如何有条件地激活一个bean?

1 个答案:

答案 0 :(得分:1)

请注意@ConditionalOnBean文档中指出:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

请注意All the requirements must be met for the condition to match, but they do not have to be met by the same bean. `

部分

如果存在类型but they do not have to be met by the same bean.中的任何bean加上任何SomeAdapter注释的bean

,则以下条件将匹配
@Blue

因此,当您将@ConditionalOnBean(value = SomeAdapter.class, annotation = Blue.class) bean标记为BlueService时,您还拥有一个@Blue,即条件通过的GreenAdapter。它欺骗我们以为它只会与带有SomeAdapter.class注释的SomeAdapter匹配。

要使您的示例生效,只需从@Blue删除@Blue注释


看看BlueService类上的getMatchingBeans方法。您会看到条件是单独评估的。