【问题标题】:Multiple implementations in SpringSpring中的多种实现
【发布时间】:2019-04-17 12:26:36
【问题描述】:

我有 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&lt;com.topic.service.TopicGenerator&gt;' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

(早些时候,当我使用字段注入而不是构造函数时,我能够在 3 个实现之一之前添加 @Service,并且代码正在处理该单个实现,但它不是我想要的)

【问题讨论】:

  • CppTopicGenerator 等实际上在哪里声明为 beans?我只看课。您需要使用构造型注释它们,或使用@Configuration 类。
  • @Michael 我尝试用构造型注释它们(在我尝试服务注释或组件注释的那 3 个类之前),出现错误原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:否TopicFacade 类型的合格 bean 可用:预计至少有 1 个 bean 有资格作为 autowire 候选。依赖注释:{}
  • @degath 如果你想使用依赖注入,你必须用构造型注释 every 类。所以每个TopicGeneratorServiceFacade 都需要一个原型注解
  • @Lino by every 你是说那三个?正确的?然后检查我的最后评论。我这样做了,但出现了错误。我尝试了服务和组件注释。
  • Is there an unresolvable circular reference 意味着你有一个类 A 使用类 BB 使用 A。如果是这种情况,您将不得不考虑您的应用程序结构

标签: java spring spring-boot dependency-injection


【解决方案1】:

可以定义List&lt;TopicGenerator&gt; 类型的bean,如下所示:

@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);
    }
}

有了这个,你的原始代码应该可以正常工作了。

Beans 可以用它们各自的 Class Name 的 camelCase 来引用。例如cppTopicGenerator 将引用 CppTopicGenerator.java 类的 bean。虽然使用@Qualifier 更清楚是一种好习惯。

【讨论】:

  • 是的,这也是一个解决方案。我也用过这种方法。
【解决方案2】:

使用限定符注释。 https://www.tutorialspoint.com/spring/spring_qualifier_annotation.htm

https://stackoverflow.com/a/40844528/4587961

那么你的 Facade 就可以拥有所有这些实现。而且您有一个方法可以根据您的条件返回特定的实现。

然后在自动装配所有依赖项后初始化列表。 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 thereinitialize topicGenerators
  • 谢谢,我会尽快检查的。
  • 还将包含服务的列表移动到 TopicFacade 类中。 TopicServiceImpl中不需要它们
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
  • 1970-01-01
  • 2013-12-20
  • 2019-05-14
相关资源
最近更新 更多