【问题标题】:Spring unable to wire a generic bean - No qualifying bean of typeSpring 无法连接通用 bean - 没有符合条件的 bean 类型
【发布时间】:2021-10-28 08:44:49
【问题描述】:

我正在处理使用 Spring Batch 编写的批处理,并且我有一个读取器/写入器组件,可以轻松地将其用于同一进程的多个实例化。 reader 和 writer 都是通用的,并且依赖于接口来实现其功能,但由于某些奇怪的原因,无法自动装配通用类型。这是我的设置。

我有一个接口,这样描述要执行的步骤,我有这个接口的 11 个实现:

import java.util.List;

public interface Process<E> {

    List<E> determineChanges(List<Integer> approvalIds);

    void applyChanges(List<E> changeCto);
}

接下来我定义了读写器实现如下:

import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@StepScope
public class GenericApprovalReader<T extends Process<U>, U> implements ItemReader<List<U>> {

    private final SomeOtherBeanStepScopedBean otherBean;

    private final T processor;

    @Autowired
    public GenericApprovalReader(SomeOtherBeanStepScopedBean otherBean,
                                 T processor) {
        this.SomeOtherBean = otherBean;
        this.processor= processor;
    }

    @Override
    public List<U> read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        List<Integer> items = this.someOtherBean.read();

        if(items != null) {
            return processor.determineChanges(items );
        } else {
            return null;
        }
    }
}

同样,我有一个作家:

import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@StepScope
// Note that second type parameter is necessary only due to necessity to parametrize the ItermWriter<List<U>> with the
// same type as is used for parametrization of Approval<U>
public class GenericApprovalWriter<T extends Process<U>, U> implements ItemWriter<List<U>> {

    private final T processor;

    @Autowired
    public GenericApprovalWriter(T processor) {
        this.approvalProcessor = processor;
    }

    @Override
    public void write(List<? extends List<U>> items) throws Exception {
        for(List<U> item: items) {
            this.processor.applyChanges(item);
        }
    }
}

现在,当我尝试在某些 @Configuration 类中连接我的 Step 中的读者和作者时,如下所示:

    @Bean(name="firstProcessingStep")
    Step firstProcessingStep(GenericApprovalReader<FirstProcessor, Item> reader,
                                   GenericApprovalWriter<FirstProcessor, Item> writer) {
        return stepBuilderFactory.get("firstProcessingStep")
                .<List<Item>,List<Item>>chunk(CHUNK_SIZE)
                .reader(reader)
                .writer(writer)
                .allowStartIfComplete(false)
                .build();
    }

我得到以下异常:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: 没有“?”类型的合格 bean可用:预期的单个匹配 bean,但找到 11

为什么会出现此错误?尽管指定了具体类型,为什么 Spring 无法构造正确的编写器和读取器的通用实例?

根据this other post about Autowiring of generic beans in Spring,这种行为应该在我正在使用的 Spring 4.0 之后才有可能。

【问题讨论】:

  • 如果你将 @Autowire GenericApprovalReader 阅读器作为属性而不是方法参数
  • 同样的错误也失败了。

标签: java spring spring-boot generics autowired


【解决方案1】:

预期单个匹配 bean,但在 bean 自动连接匹配 Spring Boot 应用程序上下文中的两个或多个加载的 bean 时发生。当 bean 在 Spring Boot 中自动连接时,会在上下文中找到两个或多个 bean。结果,bean 无法自动连接。考虑将其中一个 bean 标记为 @Primary,更新消费者以接受多个 bean,或使用 @Qualifier 来识别应该被消耗的 bean 预期单个匹配 bean 但找到n.

该类应使用 @Primary 进行注释。带注释的 @Primary 类被认为是自动连线中的默认类。 @Autowired 注解加载 @Primary bean 并向其添加接口或抽象变量。

像这样更改您的代码。

@Component
@Primary    
@StepScope
public class GenericApprovalReader<T extends Process<U>, U> implements ItemReader<List<U>> {
//content

@Component
@Primary    
@StepScope
 GenericApprovalWriter<T extends Process<U>, U> implements ItemWriter<List<U>> {

//content

【讨论】:

  • 问题是Spring无法解析泛型类型。无法构建通用读取器和写入器,因为 Spring 不知道将哪个 bean 注入到构造函数中。 @Primary 将如何解决问题?
  • 这是因为您在组件中使用接口来自动连接所以,这会持续错误。请通过这个link你会明白的。为什么会这样。
  • 感谢您的意见,但遗憾的是您的建议不起作用。我测试过了。
  • 你用@Qualifier注解试过了吗
  • @Qualifier 将如何帮助我?我需要通用 bean 的不同实例,问题是需要将 bean 注入其中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-15
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-20
相关资源
最近更新 更多