У меня есть такой класс конфигурации Spring, где мне нужно настроить две разные очереди:
@Configuration
public class DataQueue {
/**
* Queue to store the {@link SlowVars} read from the PLC
* @return the queue
*/
@Bean
Set<JsonNode> slowVarsQueue() {
return new CopyOnWriteArraySet<>();
}
/**
* Queue to store the {@link JsonNode} events
* @return the queue
*/
@Bean
Set<JsonNode> eventsQueue() {
return new CopyOnWriteArraySet<>();
}
}
В классе, где мне нужно использовать одну очередь, я написал:
@Log4j2
@RestController
@AllArgsConstructor
public class EventsApiImpl implements EventsApi {
private Set<JsonNode> eventsQueue;
private MariaEventService mariaEventService;
private EventManipulationService eventManipulationService;
private ObjectMapper mapper;
// lots of methods
}
к сожалению, Springs выдает ошибку, начиная с:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean
with name 'EventsApiImpl': Unsatisfied dependency expressed through constructor parameter 0:
No qualifying bean of type 'java.util.Set[com.fasterxml.jackson.databind.JsonNode]' available:
expected single matching bean but found 2: slowVarsQueue,eventsQueue
У двух bean-компонентов разные имена: одно — slowVarsQueue, а другое — eventsQueue, почему Spring жалуется?
Спасибо, я исправил, этот журнал пришел из другой части кода с той же проблемой.




Как указано в вашей ошибке, Spring не может решить, какой компонент использовать. Оба ваших bean-компонента предоставляют один и тот же тип данных, поэтому вам нужно определить, какой из них должен использоваться Spring.
Самый простой способ — просто добавить @Primary к компоненту, который вы хотите использовать. Вы также можете использовать @Qualifier, чтобы выбрать конкретный компонент, который вы хотите использовать.
@Qualifier: https://www.baeldung.com/spring-bean-names@Primary для одного из бобов.@Configuration
public class DataQueue {
@Bean
@Primary
Set<JsonNode> slowVarsQueue() {
return new CopyOnWriteArraySet<>();
}
@Bean
Set<JsonNode> eventsQueue() {
return new CopyOnWriteArraySet<>();
}
}
Это решение ограничивает использование вами bean-компонента eventsQueue(), то есть он будет доступен только по имени. Любой код, который требует bean-компонента типа Set<JsonNode> и не указывает имя bean-компонента, будет использовать slowVarsQueue(). Если вы хотите использовать eventsQueue() в определенном месте, вам нужно будет указать на него конкретное имя с помощью @Qualifier или других способов ссылки на компоненты по имени.
@Qualifier в аргументах конструктора.@Log4j2
@RestController
public class EventsApiImpl implements EventsApi {
private Set<JsonNode> eventsQueue;
private MariaEventService mariaEventService;
private EventManipulationService eventManipulationService;
private ObjectMapper mapper;
public EventsApiImpl(@Qualifier("eventsQueue") Set<JsonNode> eventsQueue, MariaEventService mariaEventService, EventManipulationService eventManipulationService, ObjectMapper mapper)
{
this.eventsQueue = eventsQueue;
this.mariaEventService = mariaEventService;
this.eventManipulationService = eventManipulationService;
this.mapper = mapper;
}
// lots of methods
}
Этот вариант по-прежнему сохраняет ценность обоих компонентов, а это означает, что другие части вашего кода по-прежнему будут выдавать исключение, если попытаются получить доступ к компоненту типа Set<JsonNode>. Преимущество этого заключается в том, что вы всегда знаете, к какому компоненту вы обращаетесь. Но если вы получаете доступ к этим bean-компонентам во многих местах вашего кода, вам необходимо определить @Qualifier в каждом из этих мест.
@Primary И @QualifierИспользуйте оба фрагмента кода из 1) и 2) для этого решения. Преимущество этого подхода заключается в том, что всякий раз, когда вы получаете доступ к bean-компоненту Set<JsonNode> в любом месте вашего кода, он всегда будет использовать slowVarsQueue(), не создавая исключений. Но если вы хотите использовать eventsQueue() в любом из этих мест, вы можете просто сделать это, используя @Qualifier("eventsQueue").
Насколько я понял из документации Spring, эти два компонента уже имеют разные имена: одно называется «slowVarsQueue», а другое — «eventsQueue», и это имя я использую, пытаясь их внедрить. Разве этого не достаточно для весны?
Компоненты имеют разные имена, определяемые именами методов. Ваша проблема возникает при вызове конструктора EventsApiImpl. Этот конструктор определяется аннотацией @AllArgsConstructor. Конструктор определяет только тип требуемого bean-компонента, но не определяет какой-либо bean-компонент с @Qualifier. Поскольку у вас есть два bean-компонента одного типа, сгенерированный конструктор не может решить, какой из них использовать, и выдает исключение. Использование @Primary для одного из компонентов решило бы эту проблему, поскольку конструктор затем возьмет этот компонент.
Пожалуйста, добавьте код для
slowVarsApiImpl. Это компонент, на который жалуется журнал