如何为弹簧预选赛实现OR逻辑?

gst*_*low 12 java spring autowired spring-boot

我有以下配置:

@Qualifier1
@Qualifier2
@Bean
public MyBean bean1(){...}

@Qualifier2
@Qualifier3
@Bean
public MyBean bean2(){...}

@Qualifier1
@Qualifier2
@Qualifier3
@Bean
public MyBean bean3(){...}

@Qualifier3
@Bean
public MyBean bean4(){...}

@Qualifier1
@Bean
public MyBean bean5(){...}
Run Code Online (Sandbox Code Playgroud)

这是注射的地方:

@Qualifier2
@Qualifier3
@Autowired:
private List<MyBean> beans;
Run Code Online (Sandbox Code Playgroud)

默认情况下,spring AND对每个逻辑使用逻辑@Qualifier

因此bean2,bean3将被注入。

但我想有OR逻辑的东西,所以我希望豆类bean1 bean2 bean3和bean4被注入

我该如何实现?

聚苯乙烯

@Qualifier 注释不可重复,因此我必须为每个注释创建元注释:

@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Qualifier1 {
}
Run Code Online (Sandbox Code Playgroud)

Cep*_*pr0 8

如果您使用标记接口而不是限定符怎么办?例如:

public class MyBean1 extends MyBean implements Marker1 {}

public class MyBean2 extends MyBean implements Marker2 {}

public class MyBean12 extends MyBean implements Marker1, Marker2 {}
Run Code Online (Sandbox Code Playgroud)

然后使用这个:

@Bean
public MyBean1 myBean1() {
    //...
}

@Bean
public MyBean2 myBean2() {
    //...
}

@Bean
public MyBean12 myBean12() {
    //...
}
Run Code Online (Sandbox Code Playgroud)

和这个:

@Autowired private List<Marker1> myBeans;
Run Code Online (Sandbox Code Playgroud)

你会得到的名单myBean1和myBean12豆类。

为此:

@Autowired private List<Marker2> myBeans;
Run Code Online (Sandbox Code Playgroud)

你会得到的名单myBean2和myBean12豆类。

这样行吗?

更新我

自定义FactoryBean

我实现了TagsFactoryBean类和@Tags批注,您可以使用它们来解决您的任务(我希望:))。

首先,用@Tags注释标记您的bean :

@Tags({"greeting", "2letters"})
@Bean
public Supplier<String> hi() {
    return () -> "hi";
}

@Tags({"parting", "2letters"})
@Bean
public Supplier<String> by() {
    return () -> "by";
}

@Tags("greeting")
@Bean
public Supplier<String> hello() {
    return () -> "hello";
}

@Tags("parting")
@Bean
public Supplier<String> goodbye() {
    return () -> "goodbye";
}

@Tags("other")
@Bean
public Supplier<String> other() {
    return () -> "other";
}
Run Code Online (Sandbox Code Playgroud)

然后准备TagsFactoryBean:

@Bean
public TagsFactoryBean words() {
    return TagsFactoryBean.<Supplier>builder()
            .tags("greeting", "other")
            .type(Supplier.class)
            .generics(String.class)
            .build();
}
Run Code Online (Sandbox Code Playgroud)

这tags是需要选择其bean的所需标签的数组,type是所选bean的类型,并且generics是bean 的通用类型的数组。最后一个参数是可选的,仅当您的bean是通用的时才应使用。

然后可以将其与@Qualifier注释一起使用(否则,Spring会注入所有Supplier<String>类型的bean ):

@Autowired
@Qualifier("words")
private Map<String, Supplier<String>> beans;
Run Code Online (Sandbox Code Playgroud)

该地图beans将包含三个豆类:hi,hello和other(他们的名字是地图的钥匙,它们的实例是它的值)。

您可以在测试中找到更多用法示例。

更新二

自定义AutowireCandidateResolver

感谢@bhosleviraj的推荐,我实现了TaggedAutowireCandidateResolver,它简化了自动装配所需bean的过程。只需使用相同的标记标记您的bean和自动装配的集合,即可将它们注入到集合中:

@Autowired
@Tags({"greeting", "other"})
private Map<String, Supplier<String>> greetingOrOther;

@Configuration
static class Beans {
   @Tags({"greeting", "2symbols", "even"})
   @Bean
   public Supplier<String> hi() {
      return () -> "hi";
   }

   @Tags({"parting", "2symbols", "even"})
   @Bean
   public Supplier<String> by() {
      return () -> "by";
   }

   @Tags({"greeting", "5symbols", "odd"})
   @Bean
   public Supplier<String> hello() {
      return () -> "hello";
   }

   @Tags({"parting", "7symbols", "odd"})
   @Bean
   public Supplier<String> goodbye() {
      return () -> "goodbye";
   }

   @Tags({"other", "5symbols", "odd"})
   @Bean
   public Supplier<String> other() {
      return () -> "other";
   }
}
Run Code Online (Sandbox Code Playgroud)

您不仅可以使用Map来注入bean,还可以使用其他Collections。

为了使其工作,您必须CustomAutowireConfigurer在应用程序中注册一个bean并为其提供TaggedAutowireCandidateResolver:

@Configuration
public class AutowireConfig {
   @Bean
   public CustomAutowireConfigurer autowireConfigurer(DefaultListableBeanFactory beanFactory) {
      CustomAutowireConfigurer configurer = new CustomAutowireConfigurer();
      beanFactory.setAutowireCandidateResolver(new TaggedAutowireCandidateResolver());
      configurer.postProcessBeanFactory(beanFactory);
      return configurer;
   }
}
Run Code Online (Sandbox Code Playgroud)

有关更多用法示例,请参见此测试。