Spring Batch 在流程中有两个步骤。为啥第二步永远不会运行,第一步是无限循环

Posted

技术标签:

【中文标题】Spring Batch 在流程中有两个步骤。为啥第二步永远不会运行,第一步是无限循环【英文标题】:Spring Batch with two Steps in flow. Why second step never run and first step is in infinite loopSpring Batch 在流程中有两个步骤。为什么第二步永远不会运行,第一步是无限循环 【发布时间】:2016-04-24 10:27:05 【问题描述】:

我的要求:创建一个调度程序来定期调用批处理,并且在批处理内部,我需要两个步骤。 StepA 将开始运行,根据结果,StepB 将调用。 如果您查看控制台日志,您将看到 stepA 被多次调用,比如说,完全相同的时刻。根据@Scheduled(fixedRate=60000) 每分钟应该只有一个电话。我猜这个问题与调度程序没有关系,因为我删除了调度程序并且我遇到了类似的问题。其他相关问题是从未调用过 StepB。我试图创建customDecider(“...next(customDecider()”)并创建一个私有方法来返回JobExecutionDecider。似乎两者都没有生效。 我最好的猜测是池线程在 StepA 中导致了一些“无限循环”,因为我没有正确设置一些东西,但我没有找到可能是什么。

BatchConfig.java

   /*@Bean
   public JobExecutionDecider customDecider() throws Exception
          return new CustomDecider();
   */

   private JobExecutionDecider decider(boolean decision)
          return(jobExecution, stepExecution) -> new FlowExecutionStatus(decision ? "OK" : "FAILED");
   


   @Bean
   public Job job(Step stepA, Step stepB) 
          return jobBuilderFactory.get("job1")
                       //.flow(stepA).on("FAILED").to(stepB).end().build();
                        .start(stepA)
                        .next(decider(true))
                        .on("FAILED")
                        .stop()
                        .from(stepA)
                        .next(stepB)
                        .build()
                        .build();

   

   @Bean
   public Step stepA(ItemReader<String> readerA, ItemWriter<String> writerA) 
          return stepBuilderFactory.get("stepA").<String, String> chunk(1)
                       .reader(readerA)
                       .writer(writerA)
                       .allowStartIfComplete(true)
                       .build();

   

   @Bean
   @StepScope
   public ItemReader<String> readerA() 
          return new CustomItemReaderA();

   

   @Bean
   public ItemWriter<String> writerA() 
          return new CustomItemWriterA();

   

   @Bean
   public Step stepB(ItemReader<String> readerB, ItemWriter<String> writerB) 
          return stepBuilderFactory.get("stepB").<String, String> chunk(1)
                       .reader(readerB)
                       .writer(writerB)
                       .allowStartIfComplete(true)
                       .build();

   

   @Bean
   @StepScope
   public ItemReader<String> readerB() 
          return new CustomItemReaderB();

   

   @Bean
   public ItemWriter<String> writerB() 
          return new CustomItemWriterB();

   

CustomDecider.java

public class CustomDecider implements JobExecutionDecider  


       @Override
       public FlowExecutionStatus decide(JobExecution jobExecution,
                     StepExecution stepExecution) 
              return new FlowExecutionStatus("OK");
       



CustomItemReaderA 

public class CustomItemReaderA  implements ItemReader<String>

       private static final Logger log = LoggerFactory.getLogger(CustomItemReaderA.class);
       @Override
       public String read() throws Exception, UnexpectedInputException,
                     ParseException, NonTransientResourceException 
              log.info("rA");
              return "A";
       



CustomItemWriterA 
public class CustomItemWriterA  implements ItemWriter<String>  

       private static final Logger log = LoggerFactory.getLogger(CustomItemWriterA.class);
       @Override
       public void write(List<? extends String> items) throws Exception 
              log.info("wA");

       


CustomItemReaderB 和 CustomItemReaderB 与 Custom...A 相同,只是在 log.info 期间从 A 变为 B 字母并返回

控制台日志

2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.488  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.504  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemReaderA            : rA
2016-01-18 21:40:37.519  INFO 7340 --- [pool-2-thread-1] com.example.CustomItemWriterA            : wA
and so on ...

调度器

@Component
public class QueueScheduler 

       private static final Logger log = LoggerFactory
                     .getLogger(QueueScheduler.class);

    private Job job;
    private JobLauncher jobLauncher;

    @Autowired
    public QueueScheduler(JobLauncher jobLauncher, @Qualifier("job") Job job)
        this.job = job;
        this.jobLauncher = jobLauncher;
   



   @Scheduled(fixedRate=60000)
   public void runJob()
          try
       jobLauncher.run(job, new JobParameters());
          catch(Exception ex)
                 log.info(ex.getMessage());
          
   

【问题讨论】:

【参考方案1】:

问题在于您的CustomItemReaderA。您需要告诉 Reader 何时停止“读取”数据。如果您按照下面给出的修改阅读器,执行将按预期进行。

public class CustomItemReaderA implements ItemReader<String> 
    private static final Logger log = LoggerFactory
            .getLogger(CustomItemReaderA.class);
    private int readCount = 0;

    @Override
    public String read() throws Exception, UnexpectedInputException,
            ParseException, NonTransientResourceException 
        log.info("Inside CustomItemReaderA");
        if (readCount == 1) 
            return null;
        
        readCount++;
        return "Read CustomItemReaderA";
    

【讨论】:

那么,返回 null 是停止 CustomItemReaderA 的唯一方法吗?为了避免重复调用(第二个仅用于返回 null),如果第一次成功,我可以创建一个逻辑以返回 null。如果 ItemReader 的设计考虑到了这样的想法,那么对于这种情况是可以的,但是假设有一个 CustomItemProcessorA 期望从 CustomItemReaderA 读取数据,而 CustomItemWriterA 期望从 CustomItemReaderB 处理数据,则不会返回 null 破坏此类批处理的目的还是强迫我做出一个丑陋的解决方法?还是必须至少阅读两次? 其他疑问非常接近最后一个:在我的要求中,我必须根据 CustomItemReaderA 决定是否调用 CustomItemReaderB。为此,我知道我必须以某种方式使用 JobExecutionDecider 并通过 ...on(FlowExecutionStatus) 决定它。如何更改 CustomItemReaderA 的状态?好吧,考虑两个选项(失败或成功),我可以使用 return null 表示成功并抛出异常表示失败。但是,让我们考虑三个选项?如何从 CustomItemReaderA 返回三种状态之一?我可以从 CustomItemReaderA 更改 FlowExecutionStatus 吗?

以上是关于Spring Batch 在流程中有两个步骤。为啥第二步永远不会运行,第一步是无限循环的主要内容,如果未能解决你的问题,请参考以下文章

Spring Batch StepScope Bean

(Spring Batch)为啥表'batch_job_instance'已经存在?

Spring Batch JpaItemWriter vs HibernateItemWriter 以及为啥在使用 HibernateItemWriter 时需要 HibernateTransacti

为啥在尝试对整个 Spring Batch Job 进行单元测试时出现此错误?没有可用的“org.springframework.batch.core.Job”类型的合格bean

Spring Batch - 有没有办法异步执行 TaskletStep?

Spring Batch 事务管理 - 多线程步骤