繁体   English   中英

如何在 spring 批处理中组合多个侦听器(步骤、读取、处理、写入和跳过)

[英]How to combine multiple listeners (step, read, process, write and skip) in spring batch

此操作的目的是跟踪在具有多个步骤的 spring 批处理作业中正在读取/处理/写入的行或项目。

我创建了一个实现这些接口的监听器: StepExecutionListener, SkipPolicy, ItemReadListener, ItemProcessListener, ItemWriteListener

@Component
public class GenericListener implements StepExecutionListener, SkipPolicy, ItemReadListener, ItemProcessListener, ItemWriteListener {
    private Log logger = LogFactory.getLog(getClass());
    private JobExecution jobExecution;
    private int numeroProcess = 0;
    private int currentReadIndex = 0;
    private int currentProcessIndex = 0;
    private int currentWriteIndex = 0;

    @Override
    public void beforeRead() throws Exception {
        log.info(String.format("[read][line : %s]", currentReadIndex));
        currentReadIndex++;
    }
    @Override
    public void afterRead (Object o) throws Exception {
        log.info("Ligne correct");
    }
    @Override
    public void onReadError (Exception e) throws Exception {
        jobExecution.stop();
    }
    @Override
    public boolean shouldSkip (Throwable throwable, int i) throws SkipLimitExceededException {
        String err = String.format("Erreur a la ligne %s | message %s | cause %s | stacktrace %s", numeroProcess, throwable.getMessage(), throwable.getCause().getMessage(), throwable.getCause().getStackTrace());
        log.error(err);
        return true;
    }
    @Override
    public void beforeProcess (Object o) {
        log.debug(String .format("[process:%s][%s][Object:%s]", numeroProcess++, o.getClass(), o.toString()));
        currentProcessIndex++;
    }
    @Override
    public void afterProcess (Object o, Object o2) { }
    @Override
    public void onProcessError (Object o, Exception e) {
        String err = String.format("[ProcessError at %s][Object %s][Exception %s][Trace %s]", currentProcessIndex, o.toString(), e.getMessage(), e.getStackTrace());
        log.error(err);
        jobExecution.stop();
    }
    @Override
    public void beforeWrite (List list) {
        log.info(String .format("[write][chunk number:%s][current chunk size %s]", currentWriteIndex, list != null ? list.size() : 0));
        currentWriteIndex++;
    }
    @Override
    public void afterWrite (List list) { }
    @Override
    public void onWriteError (Exception e, List list) {
        jobExecution.stop();
    }
    @Override
    public void beforeStep(StepExecution stepExecution) {
        jobExecution = stepExecution.getJobExecution();
        currentReadIndex = 0;
        currentProcessIndex = 0;
        currentWriteIndex = 0;
    }
    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return null;
    }
}

作业定义( CustomJobListener是一个简单的类,它扩展JobExecutionListenerSupport

public class BatchConfiguration {
    @Autowired
    public JobBuilderFactory jobs;

    @Bean
    public Job job(CustomJobListener listener,
                     @Qualifier("step1") Step step1,
                     @Qualifier("step2") Step step2,
                     @Qualifier("step3") Step step3) {
        return jobs.get("SimpleJobName")
                .incrementer(new RunIdIncrementer())
                .preventRestart()
                .listener(listener)
                .start(step1)
                .next(step2)
                .next(step3)
                .build();
    }
}

步骤定义(所有三个步骤的定义相同,只有读/处理器/写器更改)

@Component
public class StepControleFormat {
    @Autowired
    private StepOneReader reader;
    @Autowired
    private StepOneProcessor processor;
    @Autowired
    private StepOneWriter writer;
    @Autowired
    private ConfigAccess configAccess;
    @Autowired
    private GenericListener listener;
    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    @JobScope
    @Qualifier("step1")
    public Step stepOne() throws StepException {
        return stepBuilderFactory.get("step1")
                .<StepOneInput, StepOneOutput>chunk(configAccess.getChunkSize())
                .listener((ItemProcessListener<? super StepOneInput, ? super StepOneOutput>) listener)
                .faultTolerant()
                .skipPolicy(listener)
                .reader(reader.read())
                .processor(processor.compose())
                .writer(writer)
                .build();
    }
}

现在的问题是beforeStep(StepExecution stepExecution)afterStep(StepExecution stepExecution)方法没有被触发,但是GenericListener中的所有其他方法在它们各自的事件发生时GenericListener被正确触发。

我尝试使用listener((StepExecutionListener)listener)而不是listener((ItemProcessListener<? super StepOneInput, ? super StepOneOutput>) listener)但后者返回AbstractTaskletStepBuiler ,然后我不能使用readerprocessorwriter

更新:我的 Spring Boot 版本是:v1.5.9.RELEASE

感谢 Michael Minella 的提示,我解决了这个问题:

@Bean
@JobScope
@Qualifier("step1")
public Step stepOne() throws StepException {
    SimpleStepBuilder<StepOneInput, StepOneOutput> builder = stepBuilderFactory.get("step1")
            .<StepOneInput, StepOneOutput>chunk(configAccess.getChunkSize())
            // setting up listener for Read/Process/Write
            .listener((ItemProcessListener<? super StepOneInput, ? super StepOneOutput>) listener)
            .faultTolerant()
            // setting up listener for skipPolicy
            .skipPolicy(listener)
            .reader(reader.read())
            .processor(processor.compose())
            .writer(writer);

    // for step execution listener
    builder.listener((StepExecutionListener)listener);

    return builder.build();
}

来自StepBuilderHelper<B extends StepBuilderHelper<B>>的最后调用的listener方法public B listener(StepExecutionListener listener)返回一个StepBuilderHelper ,它不包含build()方法的定义。 所以解决方案是拆分步骤构建定义。

我不明白的是:虽然writer方法返回一个SimpleStepBuilder<I, O> ,其中包含此方法的定义public SimpleStepBuilder listener(Object listener) ,但编译器/IDE (IntelliJ IDEA) 正在调用public B listener(StepExecutionListener listener)来自StepBuilderHelper<B extends StepBuilderHelper<B>> 如果有人可以帮助解释这种行为。

此外,找到一种方法来装所有侦听器使用一个调用public SimpleStepBuilder listener(Object listener)SimpleStepBuilder将是非常有趣的。

可以按如下方式添加其他步骤侦听器。

@Bean(name = STEP1)
public Step rpcbcStep() {
    
    SimpleStepBuilder<Employee, Employee> builder = stepBuilderFactory.get(STEP1).<Employee, Employee>chunk(100)
            .reader(step1BackgroundReader())
            .processor(processor())
            .writer(writer());
            
    builder.listener(step1BackgroundStepListener)
    builder.listener(step1BackgroundStepListener2);
    // add any other listeners needed
    
    return builder.build();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM