Как я могу добиться объединения коллекций на основе аннотаций в Spring? - PullRequest
4 голосов
/ 22 октября 2019

Я пытаюсь инициализировать компонент Spring набором всех bean-компонентов определенного типа (ну, на самом деле, все, что я могу перебрать).

В базовой документации Spring говорится о объединении коллекций , но только в контексте конфигурации на основе аннотаций.

Предположим, у меня есть следующая конфигурация

@Configuration
public class MyConfig {
    @Bean
    public SomeInterface single() {
        return new SomeInterface() {};
    }

    @Bean
    public Set<SomeInterface> multi() {
        return Collections.singleton(
            new SomeInterface() {}
        );
    }
}

Где интерфейс определяется как

public interface SomeInterface {}

Iхотел бы, чтобы этот компонент получил совокупность обоих bean-компонентов - некоторую коллекцию, содержащую оба анонимных класса.

@Component
public class MyComponent {
    public MyComponent(Set<SomeInterface> allInterfaces) {
        System.out.println(allInterfaces.size()); // expecting 2, prints 1
    }
}

Я понимаю, почему Spring пришел к такому результату;он видит, что этот метод ожидает Set<SomeInterface>, а MyConfig::multi является компонентом типа Set<SomeInterface>, поэтому он автоматически связывает его с этим.

Если я изменяю подпись на Collection<SomeInterface>, он автоматически связывается с MyConfig::single. Опять же, я понимаю почему: нет ничего подходящего точно, но есть бины типа SomeInterface (в данном случае только один), поэтому он создает временную коллекцию из них и автоматически связывает их с этим. Хорошо, но не то, что мне нужно.

Я бы хотел, чтобы решение было расширяемым, чтобы при добавлении другого компонента не требовалось изменения зависимого компонента. Я попытался использовать два параметра, каждый с @Qualifier, и это работает, но не является расширяемым.

Как мне заставить это работать?

1 Ответ

4 голосов
/ 29 октября 2019

Как вы уже упоминали, MyConfig::multi - это бин типа Set<SomeInterface>, поэтому автоматическое подключение Collection<Set<SomeInterface>> даст вам все эти наборы. Следующее должно работать

public MyComponent(Collection<SomeInterface> beans,
                   Collection<Set<SomeInterface>> beanSets) {
    // merge both params here
}

Если вам нужны все реализации в нескольких местах, возможно, имеет смысл определить другой bean-компонент, содержащий объединенную коллекцию и autowire the bean:

static class SomeInterfaceCollection {
    final Set<SomeInterface> implementations;

    SomeInterfaceCollection(Set<SomeInterface> implementations) {
        this.implementations = implementations;
    }
}

@Bean
public SomeInterfaceCollection collect(Collection<SomeInterface> beans,
        Collection<Collection<SomeInterface>> beanCollections) {
    final HashSet<SomeInterface> merged = ...
    return new SomeInterfaceCollection(merged);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...