У меня есть интерфейс TopicGenerator:
public interface TopicGenerator {
File create(MultiValueMap params);
boolean accept(MultiValueMap params);
}
И 3 реализации:
@RequiredArgsConstructor
public class JavaTopicGenerator implements TopicGenerator {
//implementation ommited for readability
@RequiredArgsConstructor
public class PhpTopicGenerator implements TopicGenerator {
//implementation ommited for readability
@RequiredArgsConstructor
public class CppTopicGenerator implements TopicGenerator {
//implementation ommited for readability
Теперь я стараюсь использовать их в зависимости от моих параметров, поэтому я создал специальный TopicFacade.
@RequiredArgsConstructor
public class TopicFacade {
@NonNull
private final TopicService topicService;
@NonNull
private final List<TopicGenerator> topicGenerators;
public void generate(MultiValueMap<String, String> params, HttpServletResponse response) {
for (TopicGenerator topicGenerator : topicGenerators) {
if (topicGenerator.accept(params)) {
File tempFile = topicService.generate(params);
//do something else.
}
}
}
}
Где на моем TopicServiceImpl у меня есть:
@Service
@RequiredArgsConstructor
public class TopicServiceImpl implements TopicService {
@NonNull
private final List<TopicGenerator> reportGenerators;
public File generate(MultiValueMap params) {
for (TopicGenerator topicGenerator : topicGenerators) {
if (topicGenerator.create(params)) {
return topicGenerator.export(params);
}
}
Я получаю сообщение об ошибке:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'topicServiceImpl': Unsatisfied dependency expressed through field 'topicGenerators'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.List<com.topic.service.TopicGenerator>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
(Раньше, когда я использовал инъекцию поля вместо конструктора, я мог добавить @Service до того, как одна из трех реализаций, и код работал над этой единственной реализацией, но это не то, что я ищу)
@Michael. Я пытался аннотировать их стереотипом (до тех трех классов, которые я пробовал с помощью аннотации службы или аннотации компонентов), возникла ошибка, вызванная: org.springframework.beans.factory.NoSuchBeanDefinitionExcept ion: Нет подходящего bean-компонента типа TopicFacade. : ожидается как минимум 1 bean-компонент, который квалифицируется как кандидат autowire. Аннотации зависимостей: {}
@degath вам нужно аннотировать класс каждый стереотипом, если вы хотите использовать внедрение зависимостей. Таким образом, каждый TopicGenerator, Service и Facade нуждается в стереотипной аннотации.
@Lino by every вы имеете в виду эти 3? Правильно? Тогда проверьте мой последний комментарий. Я сделал это и получил ошибку. Я пробовал аннотации служб и компонентов.
Ооооо. Дай мне секунду проверить.
@degath с каждым, я имею в виду каждый класс, который вы хотите использовать. No qualifying bean of type TopicFacade означает, что вы также должны аннотировать TopicFacade, например, @Service
Я сделал, как вы упомянули, и теперь у меня есть Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'topicServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?
Is there an unresolvable circular reference означает, что у вас есть класс A, который использует класс B, а B использует A. Вам придется подумать о структуре своего приложения, если это так.
Я сейчас подумаю о структуре приложения. Кажется, я пока все знаю. Большое спасибо. :)
@Lino После исправления круговой ошибки у меня сейчас Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.topic.service.TopicGenerator' available: expected single matching bean but found 3: javaTopicGenerator,phpTopicGenerator ,cppTopicGenerator




Используйте аннотацию квалификатор. https://www.tutorialspoint.com/spring/spring_qualifier_annotation.htm
https://stackoverflow.com/a/40844528/4587961
Тогда ваш фасад может иметь все эти реализации. И у вас есть метод, который вернет конкретную реализацию в зависимости от вашего состояния.
Затем инициализируйте свой список после автоматического подключения всех зависимостей. https://stackoverflow.com/a/8519295/4587961
@Service // Try and play around with annotations.
public class TopicFacade {
@Autowired
@Qualifier("Service1")
private final TopicService topicService1;
//... The same stuff for other services.
@Autowired
@Qualifier("ServiceN")
private final TopicService topicServiceN;
//Initialize this in the post construct and put all your services there.
@NonNull
private final List<TopicGenerator> topicGenerators = new ArrayList();
@PostConstruct
public void initTopicGenerators() throws Exception {
topicGenerators.add(topicService1);
//And others.
topicGenerators.add(topicServiceN);
}
public void generate(MultiValueMap<String, String> params, HttpServletResponse response) {
for (ReportGenerator reportGenerator : reportGenerators) {
if (reportGenerator.accept(params)) {
File tempFile = topicService.generate(params);
//do something else.
}
}
}
}
Вы можете привести пример этого: //Initialize this in the post construct and put all your services there. Потому что я действительно не знаю, как это сделать.
Я знаю, как использовать конструкцию post для выполнения таких действий, как запуск какого-либо метода, но не знаю, как использовать генераторы тем для put all my services there и initialize.
Спасибо, проверю как можно скорее.
Также переместите список с услугами в класс TopicFacade. Вам они не нужны в TopicServiceImpl
Позвольте нам продолжить обсуждение в чате.
Можно определить bean-компонент типа List<TopicGenerator>, как показано ниже:
@Configuration
public class AppConfig {
@Autowired
private TopicGenerator cppTopicGenerator;
@Autowired
private TopicGenerator phpTopicGenerator;
@Autowired
private TopicGenerator javaTopicGenerator;
@Bean
public List<TopicGenerator> topicGeneratorList()
{
return Arrays.asList(cppTopicGenerator, phpTopicGenerator, javaTopicGenerator);
}
}
При этом ваш исходный код должен работать нормально.
На бобы можно ссылаться в camelCase их соответствующего имени класса. Например, cppTopicGenerator будет ссылаться на bean-компонент класса CppTopicGenerator.java. Хотя для большей ясности рекомендуется использовать @Qualifier.
Да, это тоже решение. Я тоже использовал этот подход.
Где
CppTopicGeneratorи т. д. Фактически объявлены как бобы? Я просто смотрю классы. Вам нужно аннотировать их стереотипом или использовать класс@Configuration.