Backend Development 17 min read

Comprehensive Spring Batch Tutorial: Architecture, Core Interfaces, and Practical Implementation

This article provides an in‑depth guide to Spring Batch, covering its overall architecture, supported business scenarios, core components such as JobRepository, JobLauncher, Job, Step, and ItemReader/Processor/Writer, and demonstrates practical implementations including Maven configuration, multi‑step jobs, parallel flows, decision logic, nested jobs, data readers, writers, processors, and scheduling integration.

Top Architect
Top Architect
Top Architect
Comprehensive Spring Batch Tutorial: Architecture, Core Interfaces, and Practical Implementation

Spring Batch is a lightweight, comprehensive batch processing framework built on Spring, designed to create robust batch applications for enterprise daily operations while leveraging Spring's productivity and POJO‑based development model.

It is not a scheduler; instead, it works alongside external schedulers like Quartz, Tivoli, or Control‑M to trigger jobs.

Business scenarios supported by Spring Batch include:

Periodic batch submissions

Concurrent batch processing (parallel job execution)

Stage‑based enterprise message‑driven processing

Large‑scale parallel batch processing

Manual or scheduled restart after failures

Ordered step processing (extendable to workflow‑driven batches)

Partial processing with record skipping (e.g., on rollback)

Transactional batch execution for small batches or existing stored procedures/scripts

Core architecture components (see table):

Name

Purpose

JobRepository

Provides persistence for Job, JobInstance, and Step metadata

JobLauncher

JobLauncher

launches a

Job

with a set of

JobParameters

Job

Job

encapsulates the entire batch process

Step

Step

represents an independent phase of a job

Core interfaces :

ItemReader : abstraction for reading a chunk of items from a Step

ItemProcessor : abstraction for business processing of each item

ItemWriter : abstraction for writing a chunk of items after processing

The typical flow is ItemReader → ItemProcessor → ItemWriter , with a Job containing multiple Step s.

1. Adding Spring Batch to a Spring Boot project

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.2.5.RELEASE</version>
</parent>
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-batch</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
  </dependency>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
  </dependency>
</dependencies>

Enable batch processing in the main class:

@SpringBootApplication
@EnableBatchProcessing
public class SpringBatchStartApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBatchStartApplication.class, args);
    }
}

2. Defining a simple job (FirstJobDemo)

@Component
public class FirstJobDemo {
    @Autowired private JobBuilderFactory jobBuilderFactory;
    @Autowired private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job firstJob() {
        return jobBuilderFactory.get("firstJob")
                .start(step())
                .build();
    }

    private Step step() {
        return stepBuilderFactory.get("step")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("执行步骤....");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
}

3. Multi‑step job with flow control

@Bean
public Job multiStepJob() {
    return jobBuilderFactory.get("multiStepJob2")
            .start(step1())
            .on(ExitStatus.COMPLETED.getExitCode()).to(step2())
            .from(step2()).on(ExitStatus.COMPLETED.getExitCode()).to(step3())
            .from(step3()).end()
            .build();
}

private Step step1() { /* similar to step2/step3 */ }
private Step step2() { /* similar to step1 */ }
private Step step3() { /* similar to step1 */ }

4. Parallel execution using split

@Bean
public Job splitJob() {
    return jobBuilderFactory.get("splitJob")
            .start(flow1())
            .split(new SimpleAsyncTaskExecutor())
            .add(flow2())
            .end()
            .build();
}

private Flow flow1() {
    return new FlowBuilder
("flow1")
            .start(step1())
            .next(step2())
            .build();
}

private Flow flow2() {
    return new FlowBuilder
("flow2")
            .start(step3())
            .build();
}

5. Decision logic (JobExecutionDecider)

@Component
public class MyDecider implements JobExecutionDecider {
    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        DayOfWeek day = LocalDate.now().getDayOfWeek();
        if (day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY) {
            return new FlowExecutionStatus("weekend");
        } else {
            return new FlowExecutionStatus("workingDay");
        }
    }
}

Job using the decider:

@Bean
public Job deciderJob() {
    return jobBuilderFactory.get("deciderJob")
            .start(step1())
            .next(myDecider)
            .from(myDecider).on("weekend").to(step2())
            .from(myDecider).on("workingDay").to(step3())
            .from(step3()).on("*").to(step4())
            .end()
            .build();
}

6. Nested jobs (JobStepBuilder)

@Bean
public Job parentJob() {
    return jobBuilderFactory.get("parentJob")
            .start(childJobOneStep())
            .next(childJobTwoStep())
            .build();
}

private Step childJobOneStep() {
    return new JobStepBuilder(new StepBuilder("childJobOneStep"))
            .job(childJobOne())
            .launcher(jobLauncher)
            .repository(jobRepository)
            .transactionManager(platformTransactionManager)
            .build();
}

private Job childJobOne() {
    return jobBuilderFactory.get("childJobOne")
            .start(stepBuilderFactory.get("childJobOneStep")
                    .tasklet((c, ctx) -> { System.out.println("子任务一执行步骤。。。"); return RepeatStatus.FINISHED; })
                    .build())
            .build();
}

7. Reading data (FlatFileItemReader example)

private ItemReader
fileItemReader() {
    FlatFileItemReader
reader = new FlatFileItemReader<>();
    reader.setResource(new ClassPathResource("reader/file"));
    reader.setLinesToSkip(1);
    DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
    tokenizer.setNames("id", "field1", "field2", "field3");
    DefaultLineMapper
mapper = new DefaultLineMapper<>();
    mapper.setLineTokenizer(tokenizer);
    mapper.setFieldSetMapper(fieldSet -> {
        TestData data = new TestData();
        data.setId(fieldSet.readInt("id"));
        data.setField1(fieldSet.readString("field1"));
        data.setField2(fieldSet.readString("field2"));
        data.setField3(fieldSet.readString("field3"));
        return data;
    });
    reader.setLineMapper(mapper);
    return reader;
}

8. Writing data (FlatFileItemWriter with JSON output)

private FlatFileItemWriter
fileItemWriter() throws Exception {
    FlatFileItemWriter
writer = new FlatFileItemWriter<>();
    FileSystemResource file = new FileSystemResource("D:/code/spring-batch-demo/src/main/resources/writer/writer-file");
    if (!Files.exists(Paths.get(file.getPath()))) {
        Files.createFile(Paths.get(file.getPath()));
    }
    writer.setResource(file);
    writer.setLineAggregator(item -> {
        try {
            return new ObjectMapper().writeValueAsString(item);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return "";
        }
    });
    writer.afterPropertiesSet();
    return writer;
}

9. Validation processor example

private BeanValidatingItemProcessor
beanValidatingItemProcessor() throws Exception {
    BeanValidatingItemProcessor
processor = new BeanValidatingItemProcessor<>();
    processor.afterPropertiesSet();
    return processor;
}

10. Scheduling the job via a REST controller

@RestController
@RequestMapping("job")
public class JobController {
    @Autowired private Job job;
    @Autowired private JobLauncher jobLauncher;

    @GetMapping("launcher/{message}")
    public String launch(@PathVariable String message) throws Exception {
        JobParameters params = new JobParametersBuilder()
                .addString("message", message)
                .toJobParameters();
        jobLauncher.run(job, params);
        return "success";
    }
}

Overall, the article walks through the complete lifecycle of a Spring Batch application—from conceptual overview and supported scenarios to concrete code examples for job configuration, step composition, parallel execution, decision making, nested jobs, data I/O, validation, and external scheduling—providing a practical reference for backend developers building robust batch solutions.

Javabackend developmentbatch processingSpring BootJob SchedulingSpring Batch
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.