[英]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
,然后我不能使用reader
、 processor
或writer
。
更新:我的 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.