【问题标题】:Spring conditional on qualified beanSpring 以合格 bean 为条件
【发布时间】:2020-03-13 14:57:28
【问题描述】:

如何在 Spring 中将 @ConditionalOnBean 与限定符一起使用?

以下独立的示例场景:我有

  • 一个服务接口SomeService
  • 一个适配器接口SomeAdapter
  • GreenService 实现带有限定符 @GreenSomeService,取决于带有限定符 @GreenSomeAdapter
  • SomeServiceSomeService 实现,带有限定符 @Blue,取决于带有限定符 @BlueSomeAdapter
  • SomeAdapter 的可选GreenAdapter 实现,带有限定符@Green
  • SomeAdapter 的可选BlueAdapter 实现,带有限定符@Blue

@Green 限定符:

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

@Blue 限定符:

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

绿色服务:

@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 {}

测试以检查 bean 激活(不包含 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());
    }
}

问题:测试无法运行,报告缺少依赖项SomeAdapter 带有限定符 @Blue 代表 BlueService)。 @ConditionalOnBean 应该禁用 bean,因为没有带有限定符 @BlueSomeAdapter,但这不起作用。

我发现当我向BlueAdapter 添加@TrueBlue 注释(与@Blue 相同,但未标记为@Annotation)并使用该注释在BlueService 上激活bean 时,它可以工作就像它应该做的那样(测试全绿色)。

总结:

  • 带有所需注释的条件 bean 激活工作(原则上)
  • 但是当需要的注解是@Qualifier 时它不起作用

这是一个错误,还是每个设计,以及如何实现这种依赖于 Spring 中合格 bean 的条件激活


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

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

【问题讨论】:

    标签: java spring dependency-injection


    【解决方案1】:

    请注意@ConditionalOnBean 文档说:

    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.的部分


    如果有来自SomeAdapter 类型的任何bean 加上带有@Blue 注释的any bean,则以下条件将匹配

    @ConditionalOnBean(value = SomeAdapter.class, annotation = Blue.class)
    

    因此,由于您有使用 @Blue 注释的 BlueService bean,并且您还有一个 GreenAdapterSomeAdapter.class,因此条件通过了。它让我们误以为它只会匹配带有@Blue 注释的SomeAdapter

    要使您的示例正常工作,只需从 BlueService 中删除 @Blue 注释


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

    【讨论】:

      猜你喜欢
      • 2018-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-11
      • 2011-03-09
      • 2017-04-29
      • 2013-06-28
      • 1970-01-01
      相关资源
      最近更新 更多