Spring Batch - 在处理器和放大器之间传递数据。作家

时间:2018-01-14 19:16:46

标签: java spring spring-boot spring-batch

我是一个春季批次,其中包含 reader-> processor-> writer

传递的数据为黑白,类型为Emp

class Emp {
    iny id;
    String name;
    EmpTypeEnum empType;    // HR, Dev, Tester, etc.

    // getters and setters
}

Reader的CSV文件中读取一个简单的批处理数据,Processor&输出CSV文件由Writer写入。

但是除了这个输出CSV文件之外,我想生成一个辅助输出文件,它只包含每个EmpType的计数,即HR,Dev&的总数。测试仪。

我在考虑仅在processor内执行计数,例如:

public class EmpItemProcessor implements ItemProcessor<Emp, Emp> {

    int countHr;
    int countDev;
    int countTester;


        @Override
        public Person process(final Emp emp) throws Exception {

        if (item.getEmpType.equals(EmpTypeEnum.HR) {
            countHr++;
        } else if // .....

        // other processor on emp

            return emp;
        }

}

但是你可以看到我只能从Emp返回Processor,那么如何从处理器&amp;中传递 countHr,countDev等。用它来创建辅助文件?

请建议。如果您认为任何其他方法会更好,请建议。

感谢

2 个答案:

答案 0 :(得分:3)

您可以使用ItemWriteListenerJobExecutionListenerSupport

  1. 定义一个ItemWriteListener,每次调用你的编写器后都会调用它。

  2. 在此Listener中,每次都在执行上下文中更新计数器

  3. 编写一个JobExecutionListener,它将在整个作业完成后调用,您可以从执行上下文中读取值并进行进一步处理。

    @Component
    @JobScope
    public class EmployeeWriteListener implements ItemWriteListener<Emp> {
    
      @Value("#{jobExecution.executionContext}")
      private ExecutionContext executionContext;
    
    
      @Override
      public void afterWrite(final List<? extends Emp> paramList) {
    
         final int counter =
              this.executionContext.getInt("TOTAL_EXPORTED_ITEMS", 0);
          this.executionContext.putInt("TOTAL_EXPORTED_ITEMS", counter + 1);
        }
    
      }
    }
    
    
    
    @Component
    @JobScope
    public class EmployeeNotificationListener extends JobExecutionListenerSupport  {
    
    @Override
    public void afterJob(final JobExecution jobExecution) {
    
      jobExecution.getExecutionContext()
          .getInt("TOTAL_EXPORTED_ITEMS")
      ...................
       }
     }
    
  4. 在宣布步骤和工作时,您应该注册这些听众。

    this.jobBuilders.get("someJob").incrementer(new RunIdIncrementer()).listener(new EmployeeNotificationListener())
            .flow(this.getSomeStep()).end().build();
    //instead of new(..) you should Autowire listener
    
    public Step getSomeStep() {
    
      return stepBuilders.get("someStep").<X, Y>chunk(10)
          .reader(this.yourReader).processor(this.yourProcessor)
          .writer(this.yourProcessor).listener(this.EmployeeWriteListener)
          .build();
    }
    

答案 1 :(得分:1)

基本上你需要多个ItemWriter来处理两个不同的写作任务。您可以轻松使用CompositeItemWriter,它可以在其中保存不同ItemWriter的列表。在每个项目上,它将调用所有ItemWriter

在你的情况下,

  1. 制作两个FlatFileItemWriter - 一个用于普通的CSV输出&amp;其他的统计数据。

  2. 然后创建CompositeItemWriter<Emp>对象,并使用此方法将这些FlatFileItemWriter<Emp>添加到其中 - public void setDelegates(List<ItemWriter<Emp>> delegates)

  3. 在步骤<{p>

  4. CompositeItemWriter使用此ItemWriter

    因此,当您CompositeItemWriter被调用时,它将委托给ItemWriter,以便您添加到列表中。

    完成工作:)