1
votes

According to Spring-Batch documentation (http://docs.spring.io/spring-batch/2.2.x/reference/html/configureStep.html#controllingStepFlow), controlling step flow in an xml config file is very simple:

e.g. I could write the following job configuration:

<job id="myJob">
    <step id="step1">
        <fail on="CUSTOM_EXIT_STATUS"/>
        <next on="*" to="step2"/>
    </step>

    <step id="step2">
        <end on="1ST_EXIT_STATUS"/>
        <next on="2ND_EXIT_STATUS" to="step10"/>
        <next on="*" to="step20"/>
    </step>

    <step id="step10" next="step11" />
    <step id="step11" />

    <step id="step20" next="step21" />
    <step id="step21" next="step22" />
    <step id="step22" />
</job>

Is there a simple way defining such a job configuration in a java-config manner? (using JobBuilderFactory and so on...)

2

2 Answers

4
votes

As the documentation also mentions, we can only branch the flow based on the exit-status of a step. To be able to report a custom exit-status (possibly different from the one automatically mapped from batch-status), we must provide an afterStep method for a StepExecutionListener.

Suppose we have an initial step step1 (an instance of a Tasklet class Step1), and we want to do the following:

  • if step1 fails (e.g. by throwing a runtime exception), then the entire job should be considered as FAILED.
  • if step1 completes with an exit-status of COMPLETED-WITH-A, then we want to branch to some step step2a which supposedly handles this specific case.
  • otherwise, we stay on the main truck of the job and continue with step step2.

Now, provide an afterStep method inside Step1 class (also implementing StepExecutionListener):

private static class Step1 implements Tasklet, StepExecutionListener
{
    @Override
    public ExitStatus afterStep(StepExecution stepExecution)
    {
        logger.info("*after-step1* step-execution={}", stepExecution.toString());

        // Report a different exit-status on a random manner (just a demo!).
        // Some of these exit statuses (COMPLETED-WITH-A) are Step1-specific 
        // and are used to base a conditional flow on them.

        ExitStatus exitStatus = stepExecution.getExitStatus();
        if (!"FAILED".equals(exitStatus.getExitCode())) {
            double r = Math.random(); 
            if (r < 0.50)
                exitStatus = null; // i.e. COMPLETED
            else 
                exitStatus = new ExitStatus(
                    "COMPLETED-WITH-A", 
                    "Completed with some special condition A");
        }
        logger.info("*after-step1* reporting exit-status of {}", exitStatus);
        return exitStatus;
    }

    // .... other methods of Step1
}

Finally, build the job flow inside createJob method of our JobFactory implementation:

@Override
public Job createJob()
{
    // Assume some factories returning instances of our Tasklets
    Step step1 = step1(); 
    Step step2a = step2a();
    Step step2 = step2();

    JobBuilder jobBuilder = jobBuilderFactory.get(JOB_NAME)
        .incrementer(new RunIdIncrementer())
        .listener(listener);  // a job-level listener

    // Build job flow
    return jobBuilder
        .start(step1)
            .on("FAILED").fail()
        .from(step1)
            .on("COMPLETED-WITH-A").to(step2a)
        .from(step1)
        .next(step2)
        .end()
        .build();
}
1
votes

Maybe. If your intentions are to write something similar to a flow decider "programmatically" (using SB's framework interfaces, I mean) there is the built-in implementation and is enough for the most use cases.

Opposite to XML config you can use JavaConfig annotations if you are familiar with them; personally I prefer XML definition, but it's only a personal opinion.