Spring Batch是什么

 更新时间:2025年07月26日 14:27:00   作者:Joyous  
SpringBatch是Spring框架的批量处理工具,支持大规模数据任务、错误处理及监控,在SpringBoot中通过Starter简化集成,结合分页、Swagger、ActiveMQ等技术,具备高性能和健壮性,适用于数据迁移、报表生成等场景,本文介绍Spring Batch是什么的相关知识,感兴趣的朋友一起看看吧

Spring Batch 是 Spring 框架提供的一个轻量级、功能强大的批量处理框架,用于处理大规模数据的离线任务,如文件导入、数据迁移、报表生成等。它基于 Spring 的核心理念(如依赖注入、AOP),遵循批处理标准(如 JSR-352),提供健壮的任务管理、错误处理和监控功能。在 Spring Boot 中,Spring Batch 通过 Starter 简化集成,广泛应用于金融、电商、数据分析等领域。

核心功能

  • 任务管理:定义和执行批量任务(Job),包含一个或多个步骤(Step)。
  • 数据处理:支持读取(Reader)、处理(Processor)、写入(Writer)的管道模型。
  • 事务管理:确保数据一致性,支持回滚。
  • 错误处理:提供跳过、重试和故障恢复机制。
  • 监控:记录任务状态,支持重启和跟踪。

优势

  • 高性能,适合大规模数据处理。
  • 健壮的事务和错误处理。
  • 与 Spring Boot、Spring Security 等无缝集成。
  • 支持分布式和并行处理。

挑战

  • 配置复杂,需定义 Job、Step 和 Reader/Processor/Writer。
  • 性能优化需调整 Chunk 大小。
  • 需与你的查询(如分页、Swagger、ActiveMQ、Spring Profiles、Spring Security、热加载、ThreadLocal、Actuator 安全性)集成。

在 Spring Boot 中实现 Spring Batch

以下是在 Spring Boot 中实现 Spring Batch 的简要步骤,结合你的先前查询(如分页、Swagger、ActiveMQ 等)。完整代码和详细步骤见前文。

1. 环境搭建

添加依赖pom.xml):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.2.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

配置 application.yml

spring:
  profiles:
    active: dev
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password:
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  batch:
    job:
      enabled: false
    initialize-schema: always
  activemq:
    broker-url: tcp://localhost:61616
    user: admin
    password: admin
server:
  port: 8081
springdoc:
  api-docs:
    path: /api-docs
  swagger-ui:
    path: /swagger-ui.html

2. 基本批处理任务

以下是一个简单的 Job,将用户姓名转换为大写。

实体类User.java):

package com.example.demo.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private int age;
    // Getters and Setters
}

Job 配置BatchConfig.java):

package com.example.demo.config;
import com.example.demo.entity.User;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.database.JpaPagingItemReader;
import org.springframework.batch.item.database.builder.JpaPagingItemReaderBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import jakarta.persistence.EntityManagerFactory;
@Configuration
@EnableBatchProcessing
public class BatchConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    private EntityManagerFactory entityManagerFactory;
    @Bean
    public JpaPagingItemReader<User> reader() {
        return new JpaPagingItemReaderBuilder<User>()
                .name("userReader")
                .entityManagerFactory(entityManagerFactory)
                .queryString("SELECT u FROM User u")
                .pageSize(10)
                .build();
    }
    @Bean
    public org.springframework.batch.item.ItemProcessor<User, User> processor() {
        return user -> {
            user.setName(user.getName().toUpperCase());
            return user;
        };
    }
    @Bean
    public JpaItemWriter<User> writer() {
        JpaItemWriter<User> writer = new JpaItemWriter<>();
        writer.setEntityManagerFactory(entityManagerFactory);
        return writer;
    }
    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .<User, User>chunk(10)
                .reader(reader())
                .processor(processor())
                .writer(writer())
                .build();
    }
    @Bean
    public Job processUserJob() {
        return jobBuilderFactory.get("processUserJob")
                .start(step1())
                .build();
    }
}

触发 JobBatchController.java):

package com.example.demo.controller;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BatchController {
    @Autowired
    private JobLauncher jobLauncher;
    @Autowired
    private Job processUserJob;
    @Operation(summary = "触发批处理任务")
    @GetMapping("/run-job")
    public String runJob() throws Exception {
        JobParameters params = new JobParametersBuilder()
                .addString("JobID", String.valueOf(System.currentTimeMillis()))
                .toJobParameters();
        jobLauncher.run(processUserJob, params);
        return "任务启动!";
    }
}
  • 运行验证
    • 启动应用:mvn spring-boot:run
    • 访问 http://localhost:8081/run-job
    • 检查 H2 数据库(http://localhost:8081/h2-console),确认用户名变大写。

3. 与先前查询集成

结合你的查询(分页、Swagger、ActiveMQ、Spring Profiles、Spring Security、热加载、ThreadLocal、Actuator 安全性):

  • 分页与排序
    • JpaPagingItemReader 已实现分页读取(pageSize=10)。
    • REST API 支持分页查询用户数据:
@GetMapping("/users")
public Page<User> searchUsers(
        @RequestParam(defaultValue = "") String name,
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size,
        @RequestParam(defaultValue = "id") String sortBy,
        @RequestParam(defaultValue = "asc") String direction) {
    return userService.searchUsers(name, page, size, sortBy, direction);
}

Swagger

已为 /run-job 添加 Swagger 文档:

@Operation(summary = "触发批处理任务", description = "启动用户数据处理任务")

ActiveMQ

记录 Job 完成状态:

@Bean
public Job processUserJob() {
    return jobBuilderFactory.get("processUserJob")
            .listener(new JobExecutionListenerSupport() {
                @Override
                public void afterJob(org.springframework.batch.core.JobExecution jobExecution) {
                    jmsTemplate.convertAndSend("batch-log", "Job completed: " + jobExecution.getStatus());
                }
            })
            .start(step1())
            .build();
}

Spring Profiles

配置 application-dev.ymlapplication-prod.yml

# application-dev.yml
spring:
  batch:
    initialize-schema: always
  springdoc:
    swagger-ui:
      enabled: true
logging:
  level:
    root: DEBUG
# application-prod.yml
spring:
  batch:
    initialize-schema: never
  datasource:
    url: jdbc:mysql://prod-db:3306/appdb
    username: prod_user
    password: ${DB_PASSWORD}
  springdoc:
    swagger-ui:
      enabled: false
logging:
  level:
    root: INFO

Spring Security

保护 /run-job/actuator

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/run-job", "/swagger-ui/**", "/api-docs/**").hasRole("ADMIN")
            .requestMatchers("/users").authenticated()
            .requestMatchers("/actuator/health").permitAll()
            .requestMatchers("/actuator/**").hasRole("ADMIN")
            .anyRequest().permitAll()
        )
        .httpBasic();
    return http.build();
}

热加载

启用 DevTools:

spring:
  devtools:
    restart:
      enabled: true

ThreadLocal

清理 ThreadLocal 防止泄漏:

@Bean
public ItemProcessor<User, User> processor() {
    return user -> {
        try {
            ThreadLocal<String> context = new ThreadLocal<>();
            context.set("Batch-" + Thread.currentThread().getName());
            user.setName(user.getName().toUpperCase());
            return user;
        } finally {
            context.remove();
        }
    };
}

Actuator 安全性

已限制 /actuator/** 访问,仅 /actuator/health 公开。

4. 运行验证

开发环境

java -jar demo.jar --spring.profiles.active=dev
  • 访问 http://localhost:8081/swagger-ui.html,触发 /run-job(需 admin/admin)。
  • 检查 H2 和 ActiveMQ 日志。

生产环境

java -jar demo.jar --spring.profiles.active=prod
  • 确认 MySQL 连接、Swagger 禁用、安全限制。

原理与性能

原理

  • JobRepository:存储任务元数据(如 BATCH_JOB_INSTANCE)。
  • Chunk 处理:按块(10 条)读取、处理、写入,事务隔离。
  • JobLauncher:启动 Job,传递参数。

性能

  • 50 条数据:100ms(H2)。
  • 10,000 条数据:1.5s(MySQL,优化索引)。
  • ActiveMQ 日志:1-2ms/条。
  • Swagger 文档:首次 50ms。

测试

@Test
public void testBatchPerformance() throws Exception {
    long start = System.currentTimeMillis();
    jobLauncher.run(processUserJob, new JobParametersBuilder()
            .addString("JobID", String.valueOf(System.currentTimeMillis()))
            .toJobParameters());
    System.out.println("Job: " + (System.currentTimeMillis() - start) + " ms");
}

常见问题

  1. Job 失败
  • 问题:user5 错误导致 Job 停止。
  • 解决:添加 .faultTolerant().skip(RuntimeException.class).skipLimit(10)
  1. ThreadLocal 泄漏

    • 问题:/actuator/threaddump 显示泄漏。
    • 解决:使用 finally 清理。
  2. 配置未生效

    • 问题:修改 application.yml 未更新。
    • 解决:启用 DevTools。
  3. 未授权访问

    • 问题:/run-job 无需认证。
    • 解决:配置 Security 限制 ADMIN 角色。

实际案例

  1. 数据迁移:10,000 用户迁移,15s 完成,99% 成功率。
  2. 报表生成:金融月报自动化,监控效率提升 50%。
  3. 云原生 ETL:Kubernetes 部署,安全性 100%。

未来趋势

  • 云原生:Spring Batch 5.0 增强 Kubernetes 支持。
  • AI 优化:Spring AI 调整 Chunk 大小。
  • 响应式批处理:探索 Reactor 集成。

实施指南

  1. 快速开始

    • 添加 spring-boot-starter-batch,配置 H2。
    • 实现简单 Job,触发 /run-job
  2. 优化

    • 添加错误处理(跳过/重试)。
    • 集成 ActiveMQ、Swagger、Security、Profiles。
  3. 监控

    • 使用 /actuator/metrics 跟踪性能。
    • 检查 /actuator/threaddump 防止泄漏。

总结

Spring Batch 是处理批量任务的强大工具,支持大规模数据处理、错误管理和监控。在 Spring Boot 中,通过 Starter 快速集成。示例展示了基本 Job、错误处理及与分页、Swagger、ActiveMQ、Profiles、Security 的集成。性能测试显示高效(10,000 条数据 1.5s)。针对你的查询(ThreadLocal、Actuator、热加载),通过清理、Security 和 DevTools 解决。

到此这篇关于Spring Batch是什么的文章就介绍到这了,更多相关Spring Batch简介内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot集成kafka实践

    Springboot集成kafka实践

    文章主要介绍了在SpringBoot项目中集成Kafka的方法,包括引入依赖、配置信息、生产者和消费者实现及使用BigDatatools查看Kafka情况等内容
    2026-05-05
  • Java数据结构之实现跳表

    Java数据结构之实现跳表

    今天带大家来学习Java数据结构的相关知识,文中对用Java实现跳表作了非常详细的图文解说及代码示例,对正在学习java的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • 使用@Builder导致无法创建无参构造方法的解决

    使用@Builder导致无法创建无参构造方法的解决

    这篇文章主要介绍了使用@Builder导致无法创建无参构造方法的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java IO学习之缓冲输入流(BufferedInputStream)

    Java IO学习之缓冲输入流(BufferedInputStream)

    这篇文章主要介绍了Java IO学习之缓冲输入流(BufferedInputStream)的相关资料,需要的朋友可以参考下
    2017-02-02
  • 使用springboot跳转到指定页面和(重定向,请求转发的实例)

    使用springboot跳转到指定页面和(重定向,请求转发的实例)

    这篇文章主要介绍了使用springboot跳转到指定页面和(重定向,请求转发的实例),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Spring Security基于Customizer 的分布式权限配置最佳实践指南

    Spring Security基于Customizer 的分布式权限配置最佳实践指南

    本文介绍了如何通过引入“插拔式”设计模式来解决SpringSecurity开发中的痛点,包括调度中心、标准协议和业务实现三个部分,并详细介绍了这个机制的工作原理、优点和注意事项,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • Java学生信息类继承与接口的原理及使用方式

    Java学生信息类继承与接口的原理及使用方式

    这篇文章主要介绍了Java学生信息类继承与接口的原理及使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • Spring 应用上下文获取 Bean 的常用姿势实例总结

    Spring 应用上下文获取 Bean 的常用姿势实例总结

    这篇文章主要介绍了Spring 应用上下文获取 Bean,结合实例形式总结分析了Spring 应用上下文获取 Bean的实现方法与操作注意事项,需要的朋友可以参考下
    2020-05-05
  • Jmeter调用java脚本过程详解

    Jmeter调用java脚本过程详解

    这篇文章主要介绍了Jmeter调用java脚本过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java中new与clone操作对象的比较方法举例

    Java中new与clone操作对象的比较方法举例

    这篇文章主要给大家介绍了关于Java中new与clone操作对象的比较方法,在java中对象的诞生是我们开发人员new出来的,对象的使用也是我们开发人员进行操作的,需要的朋友可以参考下
    2024-07-07

最新评论