Spring Batch条件流程未执行else部分

时间:2018-09-18 16:27:34

标签: java spring spring-integration spring-batch

我正在尝试使用Spring批处理实现下图中所示的流程。我指的是https://docs.spring.io/spring-batch/4.0.x/reference/pdf/spring-batch-reference.pdf的第85页上的Java配置,其中谈到了Java配置。

Requirement

由于某种原因,当决策程序返回TYPE2时,批处理以失败状态结束,而没有任何错误消息。以下是我的工作的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();

我认为尽管Java配置与Spring文档匹配,但有些不正确。此处的流程可能很有用,但是我敢肯定,没有流程,会有办法。关于如何实现这一目标的任何想法?

3 个答案:

答案 0 :(得分:2)

您不仅需要定义从决策者到下一步的流程,还需要定义从import requests from lxml import etree r = requests.get('https://s3.amazonaws.com/tripdata') source = etree.fromstring(r.content) for item in source.xpath('//*'): if item.text and item.text.endswith('zip'): print('https://s3.amazonaws.com/tripdata/' + item.text) stepType1stepType2的流程。这是一个示例:

lastStep

此打印:

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

}

如果决策者返回firstStep stepType1 lastStep ,则示例将打印:

TYPE2

希望这会有所帮助。

答案 1 :(得分:0)

遇到类似的问题,其中其他部分没有被调用(技术上仅是首先配置的on()被调用)

几乎所有与流程和决策者示例相关的网站都具有相似的工作配置,并且无法弄清问题出在哪里。

经过一些研究,发现了spring如何维持决策者和决策的方式。 在高层,在初始化应用程序时,基于作业配置,spring会维护决策者对象的决策列表(例如decsion0,decision1等)。

当我们调用Decisionr()方法时,它总是为该决策者返回一个新对象。当它返回一个新对象时,该列表仅包含每个对象的一个​​映射(即Decision0),并且由于它是一个列表,因此总是返回第一个已配置的决策。因此这就是为什么只有第一个已配置的转换才被返回的原因。叫。

解决方案: 无需对决策者进行方法调用,而是为决策者创建一个单吨级的bean并将其用于作业配置中

示例:

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

将其注入并在作业创建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)


}

希望这会有所帮助。

答案 2 :(得分:0)

创建一个dummyStep,它将返回FINISH状态并跳至下一个决策程序。您需要在完成当前步骤后将流光标重定向到下一个决策器或虚拟步骤

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