Spring Batch - 在读取器处理器和writer

时间:2016-08-24 02:08:57

标签: java spring spring-boot spring-batch batch-processing

我很好奇如何设法将读取器中的所有可用数据传递到管道中。

e.g。我希望读者将所有数据拉入并将整个结果集传递给处理器和编写器。结果集很小,我不担心资源。我以为我已经通过让所有组件(阅读器,编写器,处理器)接收并返回已处理项目的集合来正确实现这一点。

虽然这个过程的结果看起来很好,但我看到的是工作正在读取所有内容,将其传递到管道中,然后返回到读取器,读取所有内容并将其传递下来,依此类推

我考虑过创建一个额外的步骤来读取所有数据并将其传递给后续步骤,但我很好奇我是否可以这样做以及如何

工作看起来像

@Bean
Job job() throws Exception {
    return jobs.get("job").start(step1()).build()
}
@Bean
protected Step step1() throws Exception {
    return steps.get("step1").chunk(10)
    .reader(reader()
    .processor(processor()
    .writer(writer()).build()

// ...

读取器,处理器和写入器接受并返回List,例如

class DomainItemProcessor implements ItemProcessor<List<Domain>, List<Domain>>{

3 个答案:

答案 0 :(得分:4)

您也可以将其实现为tasklet。由于您希望一次处理所有数据,因此您实际上没有批处理,因此,根本不会使用“正常”弹簧批处理步骤的整个重启和失败处理。

像这样的tasklet在伪代码中可能如下所示:

@Component
public class MyTasklet implements Tasklet {

    @Autowired
    private ItemReader<YourType> readerSpringBeanName;

    @Autowired
    private ItemProcessor<List<YourType>,List<YourType>> processorSpringBeanName;

    @Autwired
    private ItemWriter<List<YourType>> writerSpringBeanName;


    RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
        readerSpringBeanName.open(new ExecutionContext());
        writerSpringBeanName.open(new ExecutionContext());

        List<YourType> items = new ArrayList<>();
        YourType readItem = readerSpringBeanName.read();
        while(readItem != null) {
             items.add(readItem);
             readItem = readerSpringBeanName.read();
        }

        writerSpringBeanName.write(processorSpringBeanName.process(items));

        readerSpringBeanName.close();
        writerSpringBeanName.close();
        return RepeatStatus.FINISHED;
    }
}

此外,根据您的使用情况,甚至可能根本不需要定义弹簧批作业。

答案 1 :(得分:0)

此案例的高级设计将是

  1. Reader将是一个自定义阅读器。它将返回List或包含Domain对象列表的包装器。读者将注入一个DAO bean来执行查询并检索域列表。
  2. 公共类DomainList {       私人列表域;

      // get/set
    

    }

    公共类DomainReader实现ItemReader {

    @Autowire
    private DomainDAO domainDAO;
    
    private List<Domain> domains;
    
    @Override
    public DomainList read() throws Exception {
        if (this.domains == null) {
            // TODO: please replace with your business logic.
            this.domains = this.domainDAO.getListofDomains();
            return this.domains;
        }
        else {
            return null;   // to tell Spring Batch the reader has done.
        }
    }
    

    }

    1. Processor and Writer将DomainList作为输入。
    2. 注意:上面是伪代码。

      谢谢, Nghia酒店

答案 2 :(得分:0)

好的,这可能为时已晚。但是这是我对实现的看法 是的,您可以使用itemreader,itemprocessor和itemwriter来实现。也许有点矫kill过正,但仍然可以做到

我看到的主要问题(由于工作不断地回到读者面前),应该有一种方法可以告诉Spring已经从Itemreader中读取了所有项目,并且没有其他要读取的对象。为此,您必须在spring尝试读取更多对象时明确返回null。

所以这是一个从ItemReader返回列表的示例 这里的read()方法应具有类似的实现方式

省略Redis实现,但这是要点,我声明一个名为-的变量

  

iterateindex

像这样在项目读取器的开头创建并初始化iterateIndex  我还包括了Redisson缓存来存储列表。再次可以否定

var main = document.getElementById("main");
var input = document.getElementById("input");
*// var v = input.value;*
var btn = document.getElementById("btn");

btn.addEventListener("click", function()
{
    var v = input.value;
    var p = document.createElement("p");
    var text = document.createTextNode(v);
    p.appendChild(text);
    main.appendChild(p);
});

并确保read()达到列表大小时返回null

    public class XXXConfigItemReader implements 
      ItemStreamReader<FeedbackConfigResponseModel> {

    private int iterateIndex;

    @Autowired
    Environment env;

    @Autowired
    RestTemplateBuilder templateBuilder;



    public DeferralConfigItemReader() {
        this.iterateIndex = 0;

    }

希望它可以帮助遇到相同问题的人。

编辑: 显示restTemplateBuilder的使用方式。请注意,您可以不用 RestTemplateBuilder 来自动接线 RestTemplate 。我利用restTemplateBuilder来满足我的prj需求

现在这是使用itemstreamreader接口实现的完整itemreader

public List<FeedbackConfigResponseModel> read()
            throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        // TODO Auto-generated method stub
        // Get the config details from db



        List<XXX> feedbackConfigModelList = new ArrayList<>;
            // store all the values from the db or read from a file , read
            //it line by line and marshall that to a list
           // now on the first itemreader call, the iterateindex will not be 
           // equal to the list size and hence the entire list is returned 
           // in the first call  

        if (feedbackConfigModelList == null || this.iterateIndex == feedbackConfigModelList.size()) {
            return null;
        } else {
            // and now we equate the list size and store it in iterateIndex
            // the second call will return null.
            this.iterateIndex = feedbackConfigModelList.size();

            return feedbackConfigModelList;
        }

    }

}