【问题标题】:Spring-batch : How to catch exception message with skip method in spring batch?Spring-batch:如何在 Spring Batch 中使用 skip 方法捕获异常消息?
【发布时间】: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。我不确定这两个监听器是否被回调。谁能告诉我我该怎么办?或者还有什么别的吗?非常感谢。

【问题讨论】:

    标签: java spring-boot spring-batch batch-processing


    【解决方案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接口。两者都应该工作正常。我在答案中添加了一个示例,显示了一个实现接口并按预期调用的侦听器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 2023-03-29
    • 2013-07-26
    • 1970-01-01
    • 2017-07-23
    • 2020-05-26
    • 1970-01-01
    相关资源
    最近更新 更多