此操作的目的是通过多个步骤跟踪在春季批处理作业中正在读取/处理/写入的行或项目。
我创建了一个实现以下接口的侦听器: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
中的所有其他方法在发生各自的事件时都被正确触发了。
我尝试使用listener((StepExecutionListener)listener)
代替listener((ItemProcessListener<? super StepOneInput, ? super StepOneOutput>) listener)
,但是后者返回AbstractTaskletStepBuiler
,然后我不能使用reader
,processor
或writer
。
更新:我的春季启动版本是:v1.5.9.RELEASE
答案 0 :(得分:0)
我解决了它,这要归功于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();
}
listener
中最后调用的public B listener(StepExecutionListener listener)
方法StepBuilderHelper<B extends StepBuilderHelper<B>>
返回一个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
连接一次呼叫中所有侦听器的方法将非常有趣。
答案 1 :(得分:0)
可以按如下方式添加其他步骤侦听器。
@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();
}