乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 批处理概述与 Spring Batch 核心理念

    • Spring Batch 概述
    • Job-Instance-Execution 三层生命周期
    • 三层架构
    • Chunk 处理模型
    • Tasklet 处理模型
  • 第2章 Job与作业配置

    • Job 详解
    • Job 配置
    • JobLauncher 详解
    • JobParameters 详解
    • JobRepository 详解
  • 第3章 Step与执行模型

    • Step 详解
    • Step 配置
    • ExecutionContext 详解
    • ItemStream 与状态管理
    • StepScope 与 JobScope
  • 第4章 ItemReader数据读取

    • ItemReader 详解
    • FlatFileItemReader 详解
    • JdbcItemReader 详解
    • MultiResourceItemReader 详解
  • 第5章 ItemProcessor 数据处理

    • ItemProcessor 详解
  • 第6章 ItemWriter 数据写出

    • ItemWriter 详解
    • FlatFileItemWriter 详解
    • CompositeItemWriter 详解
    • JdbcBatchItemWriter 详解
  • 第7章 Chunk 处理与事务边界

    • Chunk 处理模型详解
    • 事务边界
  • 第8章 作业参数与启动

    • 命令行与 Web 启动
  • 第9章 监听器与拦截器

    • 监听器详解
  • 第10章 重启重试与跳过策略

    • 重启与重试
    • 跳过策略
  • 第11章 作业流与条件决策

    • 作业流与条件决策
  • 第12章 分区与并行处理

    • 分区详解
    • 并行 Step 与 Split
  • 第13章 与 Spring Boot 集成实践

    • Spring Boot 集成
  • 第15章 运维与监控

    • 大作业设计模式
    • 运维与监控

三层架构

本章定位:掌握 Spring Batch 的分层架构设计——理解 Application、Batch Core、Batch Infrastructure 三层的职责划分和协作方式。

定义与作用

Spring Batch 采用严格的分层架构(Layered Architecture),将业务逻辑、运行时控制和基础设施解耦为三个独立层次。

飞翔科技架构师白歌在代码评审时常说:

"如果你在 ItemReader 里写了事务控制的代码,或者在 Job 定义里直接管理数据库连接,那说明你把三层职责混在一起了。Spring Batch 的每一层都有自己的边界。"

三层架构解决的问题:

问题分层解决的方案
业务逻辑和基础设施耦合Application 层只写业务,Infrastructure 层提供通用实现
状态管理和业务处理混杂Core 层统一管理所有状态,Application 层无需关心元数据表
不同场景切换困难换个 Reader 实现即可从 CSV 切换到数据库,上层代码零改动

核心原理

各层职责详解

层职责核心组件开发者需要做什么
Application(应用层)定义业务逻辑——数据从哪来、怎么处理、写到哪去Job、Step、ItemReader、ItemProcessor、ItemWriter编写具体的 Reader/Processor/Writer 实现,用 Builder API 组装 Job 和 Step
Batch Core(核心层)管理运行时状态——谁启动了 Job、执行到哪一步、事务怎么控制JobLauncher、JobRepository、JobExecution、StepExecution不需要写代码,Spring Batch 自动管理
Batch Infrastructure(基础设施层)提供通用能力——CSV 读取、JDBC 批量写入、重试策略FlatFileItemReader、JdbcBatchItemWriter、RetryPolicy直接使用内置实现或基于接口扩展自定义实现

分层带来的数据流

关键洞察:Application 层在循环中处理数据时,完全不知道 Core 层在后台默默更新元数据表。这种"无感"正是分层架构的价值——业务的归业务,状态的归状态。

完整示例

场景一:飞翔科技——从 CSV 导入学生成绩

背景:产品经理孔蓝要求将教务系统导出的学生成绩 CSV 文件导入数据库。小崔需要实现一个完整的批量导入作业。

操作前:小崔最初把所有逻辑写在一个类里

// ❌ 操作前:三层混杂——Reader、状态管理、事务控制全部耦合
public class GradeImporter {
    private Connection conn;
    private int lineNumber = 0;
    private int successCount = 0;

    public void importGrades(String csvPath) {
        try (BufferedReader br = new BufferedReader(new FileReader(csvPath))) {
            conn = DriverManager.getConnection("jdbc:mysql://...");
            conn.setAutoCommit(false);
            String line;
            while ((line = br.readLine()) != null) {
                lineNumber++;
                String[] fields = line.split(",");
                PreparedStatement ps = conn.prepareStatement(
                    "INSERT INTO grades VALUES (?, ?, ?)");
                // ... 参数设置
                ps.executeUpdate();
                successCount++;
                if (successCount % 50 == 0) {
                    conn.commit(); // 手动事务管理
                    saveProgress(lineNumber); // 手动状态持久化
                }
            }
            conn.commit();
        } catch (Exception e) {
            conn.rollback(); // 手动回滚
            throw new RuntimeException("Failed at line " + lineNumber);
        }
    }
}

操作后:按三层架构拆分

Application 层——Job 和 Step 定义:

@Configuration
@EnableBatchProcessing
public class GradeImportConfig {

    @Bean
    public Job gradeImportJob(JobRepository jobRepository,
                               Step gradeImportStep) {
        return new JobBuilder("gradeImportJob", jobRepository)
                .start(gradeImportStep)
                .build();
    }

    @Bean
    public Step gradeImportStep(JobRepository jobRepository,
                                 PlatformTransactionManager tx,
                                 FlatFileItemReader<GradeDTO> reader,
                                 ItemProcessor<GradeDTO, GradeEntity> processor,
                                 JdbcBatchItemWriter<GradeEntity> writer) {
        return new StepBuilder("gradeImportStep", jobRepository)
                .<GradeDTO, GradeEntity>chunk(50, tx)
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .build();
    }
}

Application 层——Processor(业务逻辑):

@Component
public class GradeProcessor implements ItemProcessor<GradeDTO, GradeEntity> {

    @Override
    public GradeEntity process(GradeDTO dto) {
        // 业务逻辑:转换 + GPA 计算
        GradeEntity entity = new GradeEntity();
        entity.setStudentId(dto.getStudentId());
        entity.setCourseName(dto.getCourseName());
        entity.setScore(dto.getScore());
        entity.setGpa(calculateGpa(dto.getScore())); // 业务规则
        return entity;
    }

    private double calculateGpa(double score) {
        if (score >= 90) return 4.0;
        if (score >= 85) return 3.7;
        if (score >= 80) return 3.3;
        if (score >= 75) return 3.0;
        if (score >= 70) return 2.7;
        if (score >= 60) return 2.0;
        return 0.0;
    }
}

操作前后对比:

维度操作前(混杂版)操作后(三层架构版)
代码行数约 80 行(全部混在一起)Application 约 50 行 + Infrastructure 0 行(直接复用)
事务管理手动 commit/rollback声明式:chunk(50, tx)
状态持久化手动 saveProgress()Core 层自动写入 BATCH_STEP_EXECUTION
可测试性需要真实数据库和 CSV 文件Processor 可独立单元测试
复用性Reader/Writer 逻辑不可复用FlatFileItemReader 换文件路径即可复用

场景二:数据源切换——从 CSV 改为数据库读取

背景:运营部高英反映学生数据已经从 CSV 文件迁移到了 MySQL 数据库,要求修改导入作业的数据源。

在分层架构下,只需替换 Infrastructure 层的实现,Application 层代码不改一行:

// 原来:FlatFileItemReader(CSV 读取)
@Bean
public FlatFileItemReader<GradeDTO> reader() {
    return new FlatFileItemReaderBuilder<GradeDTO>()
            .name("csvReader")
            .resource(new FileSystemResource("grades.csv"))
            .delimited().delimiter(",")
            .names("studentId", "courseName", "score")
            .targetType(GradeDTO.class)
            .build();
}

// 改为:JdbcCursorItemReader(数据库读取)—— Step 和 Processor 完全不变
@Bean
public JdbcCursorItemReader<GradeDTO> reader(DataSource dataSource) {
    return new JdbcCursorItemReaderBuilder<GradeDTO>()
            .name("dbReader")
            .dataSource(dataSource)
            .sql("SELECT student_id, course_name, score FROM grades WHERE status = 'PENDING'")
            .rowMapper(new BeanPropertyRowMapper<>(GradeDTO.class))
            .build();
}

关键点:Step 定义中的 .reader(reader) 依赖的是 ItemReader<GradeDTO> 接口,不关心具体实现。这正是分层架构中"面向接口编程"的优势。

易错场景与避坑

反例:在 Processor 中直接操作数据库

小崔最早写的 Processor 不仅做数据转换,还直接查数据库做关联:

// ❌ Processor 跨越三层:既做业务逻辑(Application),又做数据访问(Infrastructure)
@Component
public class BadProcessor implements ItemProcessor<GradeDTO, GradeEntity> {

    @Autowired
    private JdbcTemplate jdbcTemplate; // ❌ Processor 不应该直接操作数据库

    @Override
    public GradeEntity process(GradeDTO dto) {
        // 在 Processor 中查数据库做关联——破坏了层次隔离
        String studentName = jdbcTemplate.queryForObject(
            "SELECT name FROM students WHERE id = ?",
            String.class, dto.getStudentId());
        // ...
    }
}

问题:

  1. Processor 每次处理都执行一次 SQL 查询,10 万条数据就是 10 万次查询——性能灾难
  2. Processor 的事务中混入了只读查询,语义不清
  3. 单元测试需要 mock JdbcTemplate,测试复杂度上升

解决方案:将关联逻辑前置到 Reader 中(用 JOIN 查询)或后置到 Step 间的数据传递中(用 ExecutionContext 缓存)。

面试高频考点

Q1:Spring Batch 的三层架构分别对应什么职责?

Application 层(开发者编写):Job/Step 定义 + Reader/Processor/Writer 实现。Core 层(框架管理):JobLauncher/JobRepository/JobExecution/StepExecution 状态管理。Infrastructure 层(框架提供):FlatFileItemReader/JdbcBatchItemWriter/RetryPolicy 等通用实现。

Q2:三层架构中,如果我想替换 Reader 实现(比如从 CSV 换成数据库),需要改哪些代码?

只需修改 Reader Bean 的定义(Infrastructure 层的选择),Step 和 Job 定义中的 .reader(reader) 依赖的是 ItemReader<T> 接口,无需修改。这是分层架构的核心价值——上层依赖接口,下层提供实现。

Q3:为什么 Chunk 的事务管理属于 Core 层而不是 Application 层?

事务边界(每个 Chunk 一个事务)是框架层面的通用机制,与具体业务逻辑无关。无论处理学生数据还是订单数据,事务管理模式完全一致。如果放在 Application 层,每个 Job 都要自己管理事务,造成大量重复代码。


上一章:Spring Batch 概述下一章:Job-Instance-Execution 三层生命周期

上一页
Job-Instance-Execution 三层生命周期
下一页
Chunk 处理模型