Spring-batch:如何在 Spring Batch 中使用 skip 方法捕获异常消息?
Posted
技术标签:
【中文标题】Spring-batch:如何在 Spring Batch 中使用 skip 方法捕获异常消息?【英文标题】:Spring-batch : How to catch exception message with skip method in spring batch? 【发布时间】:2019-01-29 14:06:12 【问题描述】:我是春季批次的新手。 我的问题是如何在 spring-batch 中使用 skip 方法捕获异常? 据我所知,当春季批处理中发生一些异常时,我们可以使用跳过方法来跳过它们。 但是如何使用跳过方法获取异常消息? 有人建议我使用 SkipListener ,这个类有三个像 onSkipInProcess() 这样的回调方法,但它对我没有用。 而且 ItemProcessListener 也不起作用。
如下代码:(我使用skip方法忽略异常,两个监听器接收异常信息)
Step mainStep = stepBuilder.get("run")
.<ItemProcessing, ItemProcessing>chunk(5)
.faultTolerant()
.skip(IOException.class).skip(SocketTimeoutException.class)//skip IOException here
.skipLimit(2000)
.reader(reader)
.processor(processor)
.writer(writer)
.listener(stepExecListener)
.listener(new ItemProcessorListener()) //add process listener
.listener(new SkipExceptionListener()) //add skip exception listner
.build();
ItemProcessorListener 如下:
//(this class implements ItemProcessListener )
@Override
public void beforeProcess(Object item)
// TODO Auto-generated method stub
@Override
public void afterProcess(Object item, Object result)
logger.info("invoke remote finished, item=,result=",item,result);
@Override
public void onProcessError(Object item, Exception e)
logger.error("invoke remote error, item=,exception=,",item,e.getMessage(),e);
SkipExceptionListener 如下:
//(implements SkipListener<Object, Object>)
@Override
public void onSkipInRead(Throwable t)
// TODO Auto-generated method stub
@Override
public void onSkipInWrite(Object item, Throwable t)
// TODO Auto-generated method stub
@Override
public void onSkipInProcess(Object item, Throwable t)
logger.info("invoke remote finished,item=,itemJsonStr=,errMsg=,e=",
item,
JSONObject.toJSONString(item),
t.getMessage(),
t);
问题是所有记录器都不起作用。其实skip方法效果很好,我可以在表batch_step_execution中得到skip count。我不确定这两个监听器是否被回调。谁能告诉我我该怎么办?或者还有什么别的吗?非常感谢。
【问题讨论】:
【参考方案1】:spring批处理中如何用skip方法捕获异常信息?
您可以通过实现SkipListener
接口或扩展SkipListenerSupport
类来做到这一点。 SkipListener
接口中的所有方法都有一个 Throwable
参数,这是引发的异常并导致项目被跳过。您可以在此处获取异常消息。这是一个例子:
import java.util.Arrays;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.SkipListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class MyJob
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
public ItemReader<Integer> itemReader()
return new ListItemReader<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
@Bean
public ItemWriter<Integer> itemWriter()
return items ->
for (Integer item : items)
System.out.println("item = " + item);
;
@Bean
public ItemProcessor<Integer, Integer> itemProcessor()
return item ->
if (item.equals(7))
throw new IllegalArgumentException("Sevens are not accepted!!");
return item;
;
@Bean
public Step step()
return steps.get("step")
.<Integer, Integer>chunk(5)
.reader(itemReader())
.processor(itemProcessor())
.writer(itemWriter())
.faultTolerant()
.skip(IllegalArgumentException.class)
.skipLimit(3)
.listener(new MySkipListener())
.build();
@Bean
public Job job()
return jobs.get("job")
.start(step())
.build();
public static class MySkipListener implements SkipListener<Integer, Integer>
@Override
public void onSkipInRead(Throwable t)
@Override
public void onSkipInWrite(Integer item, Throwable t)
@Override
public void onSkipInProcess(Integer item, Throwable t)
System.out.println("Item " + item + " was skipped due to: " + t.getMessage());
public static void main(String[] args) throws Exception
ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
在本例中,MySkipListener
实现 SkipListener
并在您尝试执行的操作时从异常中获取消息。该示例读取从 1 到 10 的数字并跳过数字 7。您可以运行 main
方法,应该会看到以下输出:
item = 1
item = 2
item = 3
item = 4
item = 5
item = 6
item = 8
item = 9
item = 10
Item 7 was skipped due to: Sevens are not accepted!!
我希望这会有所帮助。
【讨论】:
它必须在 MyJob 类中还是只是为了方便示例? 不,它不必在MyJob
类中。为了方便起见,我在那里添加了它。该示例是自包含的,您可以运行 main 方法并查看其工作原理。
感谢您的回复!它看到我以前的代码和你没有什么不同。不知道为什么我这边不行。我明天在公司再试一次。
@MahmoudBenHassine 我认为当我在作业类中移动 Skip-Listener 时它应该可以正常工作。并像你一样将类定义为静态的。我以为静态类首先会被初始化。所以它会正常工作。但实际上它也不起作用。我认为不同之处在于您的 spring-batch 版本与我不同?我的版本是 3.0。
我使用的是 4.0.1 版,但它应该适用于 3.0 版。监听器类可以是非静态的,没关系。这是一个你可以玩的项目:github.com/benas/sandbox/tree/master/so51981640。它使用版本 3,侦听器类是非静态的,并在 MyJob 类之外定义。【参考方案2】:
我无法让它与实现 SkipListener 一起工作(很高兴知道为什么),但最后我采用了仅在文档中简要提到的注释方式。也有人在这里使用实现方法(question)遇到了类似的问题,而答案中的人使用此注释方法而不是实现接口。
示例 bean:
@Component
public class CustomSkippedListener
@OnSkipInRead
public void onSkipInRead(Throwable throwable)
@OnSkipInWrite
public void onSkipInWrite(FooWritingDTO fooWritingDTO, Throwable throwable)
LOGGER.info("balabla" + throwable.getMessage());
@OnSkipInProcess
public void onSkipInProcess(FooLoaderDTO fooLoaderDTO, Throwable throwable)
LOGGER.info("blabla" + throwable.getMessage());
private static final Logger LOGGER = LoggerFactory.getLogger(CustomSkippedListener.class);
然后像您一样自动装配并包含在步骤链中。
【讨论】:
感谢您的回复。 它可以与注解 (@OnSkipInProcess) 一起使用。我也会知道为什么实现接口不能工作。这是一个错误吗? skip listener可以是基于注解的组件,也可以实现SkipListener接口。两者都应该工作正常。我在答案中添加了一个示例,显示了一个实现接口并按预期调用的侦听器。以上是关于Spring-batch:如何在 Spring Batch 中使用 skip 方法捕获异常消息?的主要内容,如果未能解决你的问题,请参考以下文章
如何确保 SFTP 会话始终在 spring-batch 结束时关闭
Spring-batch学习总结—ItemReader普通文件,数据库,XML,多文件数据读取
spring-batch (ItemProcessor) 数据处理过程