Skip to content

Commit 967b976

Browse files
Merge pull request #155 from igorcampos-dev/feature/spring-batch-file-example
feat(spring-batch-file-example): implement Spring Batch file processi…
2 parents 7310484 + 76e5841 commit 967b976

19 files changed

+503
-235
lines changed
Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,41 @@
1-
# Spring Batch Examples | DB And Async
1+
# Spring Batch File Readers
22

3-
This project is a **Spring Boot** application demonstrating a **fully asynchronous Spring Batch job**, designed with a focus on **performance** and **scalability**.
3+
This project is a **Spring Boot** application that demonstrates how to build **custom file readers using Spring Batch**, with a strong focus on **performance**, **scalability**, and **clean design**.
4+
5+
The main goal of this repository is to showcase **different strategies for reading files** depending on their size and characteristics, following **real-world batch processing patterns**.
46

57
---
68

79
## 🚀 Overview
810

9-
The example showcases how to configure and run an **asynchronous Spring Batch job** that processes a large dataset efficiently.
10-
The job reads **10,000 records** from a database table, simulating item processing by printing
11-
`"item processed"` for each entry.
11+
The project currently provides **custom Spring Batch `ItemReader` implementations** for reading Excel files, using **different approaches for small and large files**:
12+
13+
- **Small Excel files**: loaded and processed entirely in memory
14+
- **Large Excel files**: streamed row by row to minimize memory usage
15+
16+
The architecture is intentionally extensible, allowing additional file formats (such as **CSV**) to be added in the future without changing the core batch flow.
1217

1318
---
1419

15-
## ⚙️ How It Works
20+
## 📂 Supported File Types
21+
22+
### ✅ Currently Implemented
23+
24+
- **Small Excel files (`.xlsx`)**
25+
- Suitable for files that fit comfortably in memory
26+
- Simple and fast processing
27+
28+
- **Large Excel files (`.xlsx`)**
29+
- Streaming-based reader
30+
- Designed for large datasets
31+
- Low memory footprint
32+
- Handles empty rows gracefully
33+
34+
### 🕒 Planned
35+
36+
- **CSV files**
37+
- Other structured file formats (as needed)
1638

17-
- The job leverages Spring Batch’s asynchronous capabilities to read and process data concurrently.
18-
- An **H2 in-memory database** is used to store the sample data.
19-
- The asynchronous behavior is enabled through a specific Spring profile.
2039

2140
---
2241

@@ -25,6 +44,13 @@ The job reads **10,000 records** from a database table, simulating item processi
2544
- **Java 21**
2645
- **Spring Batch**
2746
- **Spring Boot**
28-
- **H2 Database**
47+
- **Apache POI (Streaming API)**
48+
- **pjfanning**
49+
50+
---
51+
52+
## 🎯 Project Goals
2953

30-
---
54+
- Demonstrate **production-ready Spring Batch readers**
55+
- Show how to handle **large files efficiently**
56+
- Provide clean, extensible examples without framework overengineering

spring-batch-file-examples/pom.xml

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<spring.batch.excel.version>0.2.0</spring.batch.excel.version>
2929
<h2.version>2.4.240</h2.version>
3030
<jacoco.version>0.8.14</jacoco.version>
31+
<excel.streaming.reader.version>5.2.0</excel.streaming.reader.version>
3132
</properties>
3233

3334
<dependencies>
@@ -69,20 +70,6 @@
6970
<version>${instancio.version}</version>
7071
</dependency>
7172

72-
<dependency>
73-
<groupId>org.springframework.boot</groupId>
74-
<artifactId>spring-boot-starter-test</artifactId>
75-
<version>${spring.boot.version}</version>
76-
<scope>test</scope>
77-
</dependency>
78-
79-
<dependency>
80-
<groupId>org.springframework.batch</groupId>
81-
<artifactId>spring-batch-test</artifactId>
82-
<scope>test</scope>
83-
<version>${spring.batch.version}</version>
84-
</dependency>
85-
8673
<dependency>
8774
<groupId>org.springframework.batch.extensions</groupId>
8875
<artifactId>spring-batch-excel</artifactId>
@@ -102,6 +89,26 @@
10289
<version>${poi.ooxml.version}</version>
10390
</dependency>
10491

92+
<dependency>
93+
<groupId>com.github.pjfanning</groupId>
94+
<artifactId>excel-streaming-reader</artifactId>
95+
<version>${excel.streaming.reader.version}</version>
96+
</dependency>
97+
98+
<dependency>
99+
<groupId>org.springframework.boot</groupId>
100+
<artifactId>spring-boot-starter-test</artifactId>
101+
<version>${spring.boot.version}</version>
102+
<scope>test</scope>
103+
</dependency>
104+
105+
<dependency>
106+
<groupId>org.springframework.batch</groupId>
107+
<artifactId>spring-batch-test</artifactId>
108+
<scope>test</scope>
109+
<version>${spring.batch.version}</version>
110+
</dependency>
111+
105112
</dependencies>
106113

107114
<build>

spring-batch-file-examples/src/main/java/com/io/example/README.md

Lines changed: 0 additions & 38 deletions
This file was deleted.

spring-batch-file-examples/src/main/java/com/io/example/config/ExcelBatchConfig.java

Lines changed: 0 additions & 91 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.io.example.config;
2+
3+
import com.io.example.dto.StudentDto;
4+
import com.io.example.reader.StreamingExcelItemReader;
5+
import com.io.example.service.StudentService;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.batch.core.Step;
8+
import org.springframework.batch.core.configuration.annotation.StepScope;
9+
import org.springframework.batch.core.repository.JobRepository;
10+
import org.springframework.batch.core.step.builder.StepBuilder;
11+
import org.springframework.batch.item.ItemProcessor;
12+
import org.springframework.batch.item.ItemWriter;
13+
import org.springframework.beans.factory.annotation.Value;
14+
import org.springframework.context.annotation.Bean;
15+
import org.springframework.context.annotation.Configuration;
16+
import org.springframework.core.io.ClassPathResource;
17+
import org.springframework.transaction.PlatformTransactionManager;
18+
19+
import java.time.LocalDate;
20+
21+
@Configuration
22+
@RequiredArgsConstructor
23+
public class LargeExcelReadBatchConfig {
24+
25+
private final StudentService studentService;
26+
27+
@Bean
28+
@StepScope
29+
public StreamingExcelItemReader<StudentDto> largeExcelReader(
30+
@Value("#{jobParameters['filePath']}") String filePath
31+
) {
32+
return new StreamingExcelItemReader<>(
33+
new ClassPathResource(filePath),
34+
row -> new StudentDto(
35+
row.getCell(0).getStringCellValue(),
36+
row.getCell(1).getStringCellValue(),
37+
LocalDate.parse(row.getCell(2).getStringCellValue())
38+
)
39+
);
40+
}
41+
42+
@Bean
43+
public ItemProcessor<StudentDto, StudentDto> largeExcelProcessor() {
44+
return student -> student;
45+
}
46+
47+
@Bean
48+
public ItemWriter<StudentDto> largeExcelWriter() {
49+
return items -> items.forEach(studentService::print);
50+
}
51+
52+
@Bean
53+
public Step largeExcelStep(
54+
JobRepository jobRepository,
55+
PlatformTransactionManager transactionManager,
56+
StreamingExcelItemReader<StudentDto> largeExcelReader,
57+
ItemProcessor<StudentDto, StudentDto> largeExcelProcessor,
58+
ItemWriter<StudentDto> largeExcelWriter,
59+
@Value("${spring.batch.chunk-size}") int chunkSize
60+
) {
61+
return new StepBuilder("largeExcelStep", jobRepository)
62+
.<StudentDto, StudentDto>chunk(chunkSize, transactionManager)
63+
.reader(largeExcelReader)
64+
.processor(largeExcelProcessor)
65+
.writer(largeExcelWriter)
66+
.build();
67+
}
68+
69+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.io.example.config;
2+
3+
import com.io.example.dto.StudentDto;
4+
import com.io.example.mapper.StudentMapper;
5+
import com.io.example.service.StudentService;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.batch.core.Step;
8+
import org.springframework.batch.core.configuration.annotation.StepScope;
9+
import org.springframework.batch.core.repository.JobRepository;
10+
import org.springframework.batch.core.step.builder.StepBuilder;
11+
import org.springframework.batch.extensions.excel.poi.PoiItemReader;
12+
import org.springframework.batch.item.ItemProcessor;
13+
import org.springframework.batch.item.ItemWriter;
14+
import org.springframework.beans.factory.annotation.Value;
15+
import org.springframework.context.annotation.Bean;
16+
import org.springframework.context.annotation.Configuration;
17+
import org.springframework.core.io.ClassPathResource;
18+
import org.springframework.transaction.PlatformTransactionManager;
19+
20+
@Configuration
21+
@RequiredArgsConstructor
22+
public class SmallExcelReadBatchConfig {
23+
24+
private final StudentService studentService;
25+
26+
@Bean
27+
@StepScope
28+
public PoiItemReader<StudentDto> smallExcelReader(
29+
@Value("#{jobParameters['filePath']}") String filePath
30+
) {
31+
PoiItemReader<StudentDto> reader = new PoiItemReader<>();
32+
reader.setResource(new ClassPathResource(filePath));
33+
reader.setLinesToSkip(1);
34+
reader.setRowMapper(new StudentMapper());
35+
return reader;
36+
}
37+
38+
@Bean
39+
public ItemProcessor<StudentDto, StudentDto> smallExcelProcessor() {
40+
return student -> student;
41+
}
42+
43+
@Bean
44+
public ItemWriter<StudentDto> smallExcelWriter() {
45+
return items -> items.forEach(studentService::print);
46+
}
47+
48+
@Bean
49+
public Step smallExcelStep(JobRepository jobRepository,
50+
PlatformTransactionManager transactionManager,
51+
PoiItemReader<StudentDto> smallExcelReader,
52+
ItemProcessor<StudentDto, StudentDto> smallExcelProcessor,
53+
ItemWriter<StudentDto> smallExcelWriter,
54+
@Value("${spring.batch.chunk-size}") int chunkSize) {
55+
56+
return new StepBuilder("smallExcelStep", jobRepository)
57+
.<StudentDto, StudentDto>chunk(chunkSize, transactionManager)
58+
.reader(smallExcelReader)
59+
.processor(smallExcelProcessor)
60+
.writer(smallExcelWriter)
61+
.build();
62+
}
63+
}

0 commit comments

Comments
 (0)