簡體   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