Ответ 1
Что если вы использовали маркерные интерфейсы вместо квалификаторов? Например:
public class MyBean1 extends MyBean implements Marker1 {}
public class MyBean2 extends MyBean implements Marker2 {}
public class MyBean12 extends MyBean implements Marker1, Marker2 {}
Затем с помощью этого:
@Bean
public MyBean1 myBean1() {
//...
}
@Bean
public MyBean2 myBean2() {
//...
}
@Bean
public MyBean12 myBean12() {
//...
}
и это:
@Autowired private List<Marker1> myBeans;
Вы получите список бинов myBean1
и myBean12
.
И для этого:
@Autowired private List<Marker2> myBeans;
Вы получите список бинов myBean2
и myBean12
.
Будет ли это работать?
ОБНОВЛЕНИЕ I
Custom FactoryBean
Я реализовал класс TagsFactoryBean и аннотацию @Tags, которые вы можете использовать для решения своей задачи (я надеюсь :)).
Во-первых, пометьте свои бобы аннотацией @Tags
:
@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";
}
Затем подготовьте TagsFactoryBean
:
@Bean
public TagsFactoryBean words() {
return TagsFactoryBean.<Supplier>builder()
.tags("greeting", "other")
.type(Supplier.class)
.generics(String.class)
.build();
}
Здесь tags
- это массив желаемых тегов, чьи бины должны быть выбраны, type
- это выбранный тип бинов, а generics
- это массив универсальных типов бинов. Последний параметр является необязательным и должен использоваться только в том случае, если ваши компоненты являются общими.
Затем вы можете использовать его с аннотацией @Qualifier
(в противном случае Spring вводит все компоненты типа Supplier<String>
):
@Autowired
@Qualifier("words")
private Map<String, Supplier<String>> beans;
Карта beans
будет содержать три bean-компонента: hi
, hello
и other
(их имена являются ключами карты, а их экземпляры - ее значениями).
Дополнительные примеры использования вы можете найти в тестах.
ОБНОВЛЕНИЕ II
Пользовательский AutowireCandidateResolver
Благодаря рекомендации @bhosleviraj recommendation я реализовал TaggedAutowireCandidateResolver, который упрощает процесс автоматической разметки нужных бинов. Просто пометьте свои бобы и коллекцию с автопроводкой одинаковыми тегами, и вы добавите их в коллекцию:
@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";
}
}
Вы можете использовать не только Карту для инъекций бобов, но и другие Коллекции.
Чтобы заставить его работать, вы должны зарегистрировать bean-компонент CustomAutowireConfigurer
в своем приложении и предоставить ему TaggedAutowireCandidateResolver
:
@Configuration
public class AutowireConfig {
@Bean
public CustomAutowireConfigurer autowireConfigurer(DefaultListableBeanFactory beanFactory) {
CustomAutowireConfigurer configurer = new CustomAutowireConfigurer();
beanFactory.setAutowireCandidateResolver(new TaggedAutowireCandidateResolver());
configurer.postProcessBeanFactory(beanFactory);
return configurer;
}
}
Дополнительные примеры использования см. в этом тесте.