简体   繁体   English

Spring Batch 条件流不执行 else 部分

[英]Spring Batch Conditional Flow Not executing the else part

I am trying to achieve the flow shown in the image below using Spring batch.我正在尝试使用 Spring 批处理实现下图所示的流程。 I was referring to java configuration on page 85 of https://docs.spring.io/spring-batch/4.0.x/reference/pdf/spring-batch-reference.pdf where it talks about Java Configuration.我指的是https://docs.spring.io/spring-batch/4.0.x/reference/pdf/spring-batch-reference.pdf 的第 85 页上的 java 配置,它讨论了 Java 配置。

要求

For some reason, when the Decider returns TYPE2, the batch ends with Failed State without any error message.出于某种原因,当判定器返回 TYPE2 时,批处理以失败状态结束,没有任何错误消息。 Following is the java configuration of my job:以下是我工作的java配置:

jobBuilderFactory.get("myJob")
            .incrementer(new RunIdIncrementer())
            .preventRestart()
            .start(firstStep())
            .next(typeDecider()).on("TYPE1").to(stepType1()).next(lastStep())
            .from(typeDecider()).on("TYPE2").to(stepType2()).next(lastStep())
            .end()
            .build();

I think something not right with the java configuration though it matches with the Spring document.我认为 java 配置有问题,尽管它与 Spring 文档匹配。 A flow can be useful here but I am sure there would be a way without it.流程在这里很有用,但我相信没有它会有办法。 Any idea on how to achieve this?关于如何实现这一目标的任何想法?

You need to define the flow not only from the decider to next steps but also starting from stepType1 and stepType2 to lastStep .您不仅需要定义从stepType1到后续步骤的流程,还需要定义从stepType1stepType2lastStep Here is an example:下面是一个例子:

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
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.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.repeat.RepeatStatus;
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 Step firstStep() {
        return steps.get("firstStep")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("firstStep");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public JobExecutionDecider decider() {
        return (jobExecution, stepExecution) -> new FlowExecutionStatus("TYPE1"); // or TYPE2
    }

    @Bean
    public Step stepType1() {
        return steps.get("stepType1")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("stepType1");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step stepType2() {
        return steps.get("stepType2")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("stepType2");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step lastStep() {
        return steps.get("lastStep")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("lastStep");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(firstStep())
                .next(decider())
                    .on("TYPE1").to(stepType1())
                    .from(decider()).on("TYPE2").to(stepType2())
                    .from(stepType1()).on("*").to(lastStep())
                    .from(stepType2()).on("*").to(lastStep())
                    .build()
                .build();
    }

    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());
    }

}

This prints:这打印:

firstStep
stepType1
lastStep

If the decider returns TYPE2 , the sample prints:如果决策程序返回TYPE2 ,则示例打印:

firstStep
stepType2
lastStep

Hope this helps.希望这可以帮助。

Ran into the similar issue where else part is not being called (technically only first configured on() is being called)遇到了类似的问题,即没有调用 else 部分(从技术上讲,只调用了首先配置的 on())

Almost all the websites related to the flow and decider examples have the similar job configurations and was not able to figure it out what was the issue.几乎所有与流程和决策程序示例相关的网站都有类似的作业配置,无法弄清楚是什么问题。

After some research, found the way how spring maintains the deciders and decisions.经过一些研究,找到了 spring 如何维护决策者和决策的方式。 At high level, while initializing the application, based on the job configuration spring maintains a list of decisions for a decider object (like decsion0, decision1, so on).在高层,在初始化应用程序时,spring 基于作业配置维护决策对象(如 decsion0、decision1 等)的决策列表。

when we call the decider() method it always returns a new object for the decider.当我们调用决策者()方法时,它总是为决策者返回一个新对象。 As it is returning a new object, the list contains only one mapping for each object (ie, decision0 ) and since it is a list, it always return the first configured decision.So this is the reason why only the first configured transition only being called.当它返回一个新对象时,该列表只包含每个对象的一个​​映射(即 decision0 )并且由于它是一个列表,它总是返回第一个配置的决策。所以这就是为什么只有第一个配置的转换才被叫。

Solution: Instead of making a method call to the decider, create a single-ton bean for the decider and use it in the job configuration解决方案:不是对决策程序进行方法调用,而是为决策程序创建一个单例 bean 并在作业配置中使用它

Example:例子:

@Bean
public JobExecutionDecider stepDecider() {
    return new CustomStepDecider();
}

inject it and use it in the job creation bean注入它并在作业创建 bean 中使用它

@Bean
public Job sampleJob(Step step1, Step step2,Step step3,
JobExecutionDecider stepDecider) {

return jobBuilderFactory.get("sampleJob")                    
        .start(step1)
        .next(stepDecider).on("TYPE1").to(step2)
        .from(stepDecider).on("TYPE2").to(step3)


}

Hope this helps.希望这可以帮助。

Create a dummyStep which will return the FINISH status and jump to next decider.创建一个 dummyStep,它将返回 FINISH 状态并跳转到下一个决策程序。 you need to redirect flow cursor to next decider or virtual step after finishing the current step完成当前步骤后,您需要将流光标重定向到下一个决策程序或虚拟步骤

.next(copySourceFilesStep())
.next(firstStepDecider).on(STEP_CONTINUE).to(executeStep_1())
.from(firstStepDecider).on(STEP_SKIP).to(virtualStep_1())

//-executeStep_2
.from(executeStep_1()).on(ExitStatus.COMPLETED.getExitCode())
.to(secondStepDecider).on(STEP_CONTINUE).to(executeStep_2())
.from(secondStepDecider).on(STEP_SKIP).to(virtualStep_3())

.from(virtualStep_1()).on(ExitStatus.COMPLETED.getExitCode())
.to(secondStepDecider).on(STEP_CONTINUE).to(executeStep_2())
.from(secondStepDecider).on(STEP_SKIP).to(virtualStep_3())

//-executeStep_3
.from(executeStep_2()).on(ExitStatus.COMPLETED.getExitCode())
.to(thirdStepDecider).on(STEP_CONTINUE).to(executeStep_3())
.from(thirdStepDecider).on(STEP_SKIP).to(virtualStep_4())

.from(virtualStep_3()).on(ExitStatus.COMPLETED.getExitCode())
.to(thirdStepDecider).on(STEP_CONTINUE).to(executeStep_3())
.from(thirdStepDecider).on(STEP_SKIP).to(virtualStep_4())

@Bean
public Step virtulaStep_2() {
    return stepBuilderFactory.get("continue-virtualStep2")
            .tasklet((contribution, chunkContext) -> {
                return RepeatStatus.FINISHED;
            })
            .build();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM