To separate steps class in spring batch

841 views Asked by At

I have tried to find the solution but I cannot... ㅠㅠ

I want to separate steps in a job like below.

step1.class -> step2.class -> step3.class -> done

The reason why I'm so divided is that I have to use queries each step.

    @Bean
    public Job bundleJob() {
        return jobBuilderFactory.get(JOB_NAME)
                .start(step1) // bean 
                .next(step2) // bean
                .next(step3()) // and here is the code ex) reader, processor, writer
                .build();
    }

my purpose is that I have to use the return data in step1, step2. but jpaItemReader is like async ... so it doesn't process like above order.
debug flow like this.

readerStep1 -> writerStep1 -> readerStep2 -> readerWriter2 -> readerStep3 -> writerStep3 
and
-> processorStep1 -> processorStep2 -> processorStep3

that is the big problem to me...
How can I wait each step in a job? Including querying.

2

There are 2 answers

0
Joonseo Lee On

aha! I got it.
the point is the creating beans in a configuration.
I wrote annotation bean all kinds of steps so that those are created by spring.

the solution is late binding like @JobScope or @StepScope

    @Bean
    @StepScope. // late creating bean.
    public ListItemReader<Dto> itemReader() {
        // business logic
        return new ListItemReader<>(dto);
    }
0
Vignesh T I On

To have a separate steps in your job you can use a Flow with a TaskletStep. Sharing a snippet for your reference,

@Bean
public Job processJob() throws Exception {

    Flow fetchData = (Flow) new FlowBuilder<>("fetchData")
            .start(fetchDataStep()).build();

    Flow transformData = (Flow) new FlowBuilder<>("transformData")
            .start(transformData()).build();

    Job job = jobBuilderFactory.get("processTenantLifeCycleJob").incrementer(new RunIdIncrementer())
    .start(fetchData).next(transformData).next(processData()).end()
    .listener(jobCompletionListener()).build();

    ReferenceJobFactory referenceJobFactory = new ReferenceJobFactory(job);
    registry.register(referenceJobFactory);

    return job;
}


@Bean
public TaskletStep fetchDataStep() {
    return stepBuilderFactory.get("fetchData")
            .tasklet(fetchDataValue()).listener(fetchDataStepListener()).build();
}

@Bean
@StepScope
public FetchDataValue fetchDataValue() {
    return new FetchDataValue();
}

@Bean
public TaskletStep transformDataStep() {
    return stepBuilderFactory.get("transformData")   
    .tasklet(transformValue()).listener(sendReportDataCompletionListener()).build();
}

@Bean
@StepScope
public TransformValue transformValue() {
    return new TransformValue();
}

@Bean
public Step processData() {
    return stepBuilderFactory.get("processData").<String, Data>chunk(chunkSize)
            .reader(processDataReader()).processor(dataProcessor()).writer(processDataWriter())
            .listener(processDataListener())
            .taskExecutor(backupTaskExecutor()).build();
}

In this example I have used 2 Flows to Fetch and Transform data which will execute data from a class.

In order to return the value of those from the step 1 and 2, you can store the value in the job context and retrieve that in the ProcessData Step which has a reader, processor and writer.