SkillAtlasSkill 详情

spring-batch

Production-grade Spring Boot skills for Claude Code and Codex.

审核状态:已审核Quality 80Security 100

复制安装命令

用 Codex 或 Claude 安装复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它先审查 Skill 页面再帮你安装。

复制前请先查看来源、License 和安全提示。

项目 README

来源文件:README.md

抓取于 2026年9月8日
spring-boot-skills — production-grade Claude Code and Codex skills for Spring Boot

Production-grade Spring Boot skills for Claude Code and Codex. Drop a skill into your project and your AI coding agent instantly understands your architecture, patterns, and conventions.


skills Spring Boot Java License

Claude Code Codex Spring AI MCP Java SDK GitHub Stars


Quick Start · Skills Catalog · Before / After · Skill Anatomy · Contributing


Why this exists

AI coding agents are great at Python. They hallucinate in Spring Boot.

They generate @Autowired field injection instead of constructor injection. They use ResponseEntity<?> where you have a standard response wrapper. They ignore your existing exception hierarchy and invent a new one. They don't know your project uses Flyway, so they generate schema SQL by hand. They emit pre-GA Spring AI artifact names that no longer exist in Maven Central.

Skills fix this. A skill is a markdown file your agent reads before touching your code. It tells the agent your conventions, your stack, your gotchas — not generic Spring Boot from 2020.

flowchart LR
    A["💬 You ask:<br/>&quot;add an orders endpoint&quot;"] --> B{Agent matches<br/>skill triggers}
    B -->|"REST code?"| C["📜 rest-api-conventions"]
    B -->|"persistence?"| D["📜 spring-data-jpa"]
    C --> E["🤖 Agent codes with<br/>YOUR envelope, YOUR<br/>status mapping, YOUR<br/>pagination contract"]
    D --> E
    E --> F["✅ Code that looks like<br/>your team wrote it"]

    style A fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
    style B fill:#1e293b,stroke:#94a3b8,color:#e2e8f0
    style C fill:#10241a,stroke:#6DB33F,color:#a7f3d0
    style D fill:#10241a,stroke:#6DB33F,color:#a7f3d0
    style E fill:#0f172a,stroke:#d97757,color:#e2e8f0
    style F fill:#10241a,stroke:#6DB33F,color:#a7f3d0

This repo is a collection of battle-tested skills. Copy, adapt, drop in.


🧠 Concepts

ConceptDescription
SkillsMarkdown files loaded into Claude Code or Codex context — tell the agent how to work in your codebase
CLAUDE.md / AGENTS.mdProject-level persistent memory — your agent's onboarding doc
MCP Java SDKOfficial Java SDK for building MCP servers — connect your Spring Boot app to any AI agent
Marketplace pluginsVersioned Claude Code and Codex packages for all Boot 3 or Boot 4 skills
Project templatesReady-to-adapt CLAUDE.md and AGENTS.md guidance for Boot 3 and Boot 4 projects
Planned workflowsRepeatable commands such as /generate-endpoint, /write-test, and /db-migrate are listed in the roadmap

📦 Skills

The catalog ships in two version trees — pick the folder that matches your stack. Shared topics normally have both flavors; genuinely version-specific topics may live only in the relevant tree.

FolderTarget stackCompatibility baseline
skills/spring-boot-4/Spring Boot 4.x · Spring Framework 7 · Spring Security 7 · Spring Batch 6 · Jackson 3 · Spring AI 2.0Java 17+; examples use Java 21; Boot 4.0.x and 4.1.x
skills/spring-boot-3/Spring Boot 3.x · Spring Framework 6 · Spring Security 6 · Spring Batch 5 · Jackson 2 · Spring AI 1.xJava 17+; examples use Java 21

Drop any skill folder into your agent's skills directory. Claude Code users can copy them to .claude/skills/; Codex users can adapt the same SKILL.md folders for .codex/skills/. The catalog below links to the Spring Boot 4 versions — swap spring-boot-4 for spring-boot-3 in any path if you're still on Boot 3.

The version guidance follows the Spring Boot 4 system requirements, the Spring Boot 4 migration guide, and Spring AI's compatibility guidance. Check the official release notes before upgrading a project.

Fast-moving integrations were last verified in August 2026 against Spring Boot 4.1, Spring AI 2.0, MCP Java SDK 2.0, Spring Cloud 2025.1, and Spring Cloud Gateway 5.0. Keep BOM-managed dependency versions together and recheck the linked official sources before adopting a newer release line.

Configuration

SkillDescriptionTags
configuration-propertiesTyped binding, startup validation, duration units and secret handling.configuration validation

🏗️ Architecture

SkillDescriptionTags
layered-architectureEnforces Controller → Service → Repository separation. Prevents business logic leaking into controllers or repositories.architecture
hexagonal-architecturePorts and adapters pattern for Spring Boot. Keeps domain clean of framework dependencies.architecture ddd
domain-driven-designAggregates, value objects, domain events with commit-safe publication. Includes JPA mapping conventions.ddd jpa
multi-module-mavenParent POM conventions, shared BOM, inter-module dependency rules. Prevents circular deps.maven architecture
spring-modulithModule boundaries, verification and durable event publication.architecture modulith
multi-tenancyTenant resolution, database/schema isolation, tenant-aware persistence, caches, jobs, and migrations.architecture security data

🔌 API Design

SkillDescriptionTags
rest-api-conventionsYour project's response envelope, error codes, pagination contract, versioning strategy. Fill in the template.rest api
openapi-firstGenerate controllers and DTOs from OpenAPI spec. Uses openapi-generator-maven-plugin.openapi codegen
problem-details-rfc9457RFC 9457 compliant error responses with Spring's ProblemDetail. Replaces ad-hoc error envelopes.error-handling rest
idempotency-patternsConcurrent retries, scoped request keys, replay and transaction boundaries.api transactions
hateoasSpring HATEOAS link building conventions. Teaches agent when and how to add hypermedia links.hateoas rest

🌐 Edge & Reactive

SkillDescriptionTags
spring-cloud-gatewaySecure route design, header hygiene, timeouts, rate limits, retries, and release-train compatibility.gateway spring-cloud security
webflux-reactive-patternsNon-blocking WebFlux, Reactor context, R2DBC, backpressure, cancellation, and reactive tests.webflux reactor r2dbc

🗄️ Data & Persistence

SkillDescriptionTags
spring-data-jpaBoot 4 JPA with Hibernate 7: entity modeling, Jakarta imports, relationships, projections, N+1 prevention, keyset pagination, and batch writes.jpa hibernate
flyway-migrationsMigration naming convention, safe multi-step schema changes, team workflow for concurrent migrations.flyway migrations
spring-data-redisCache-aside pattern, key naming, TTL strategy, stampede protection, serialization config.redis caching
transactional-patterns@Transactional propagation rules, self-invocation pitfall, after-commit side effects, saga pattern.transactions

📨 Messaging

SkillDescriptionTags
event-driven-messagingKafka/RabbitMQ/Pulsar/JMS contracts, idempotent consumers, outbox delivery, retries, and dead letters.messaging kafka rabbitmq

⚙️ Batch & Jobs

SkillDescriptionTags
spring-batchSpring Batch 6 chunk jobs, JDBC versus resourceless repositories, JobOperator, restartability, reader sort/thread-safety, and transaction boundaries.batch etl

🚀 Migration & Deployment

SkillDescriptionTags
spring-boot-migrationStaged Boot 3.5 → 4 migration covering modular starters, Jackson 3, tests, servers, and verification.migration spring-boot-4
container-native-deploymentBuildpacks, layered OCI images, JVM containers, GraalVM native images, AOT hints, and probes.containers graalvm aot

🧰 Framework 7 Core

SkillDescriptionTags
api-versioningSpring Framework 7 built-in API versioning: mapping versions, central request resolution, defaults, supported versions, and deprecation headers.rest api versioning
http-interface-clientsBoot 4 declarative HTTP clients with @ImportHttpServices, grouped base URLs/timeouts, and RestClient versus WebClient selection.http clients
null-safetyJSpecify nullability for Framework 7: @NullMarked, @Nullable, generic and array positions, Kotlin interop, and NullAway.null-safety jspecify
resilience-retryFramework 7 core @Retryable and @ConcurrencyLimit: enablement, backoff, no @Recover, proxy, and transaction pitfalls.resilience retry

🔒 Security

SkillDescriptionTags
spring-security-jwtJWT auth filter chain, access and refresh token validation, RBAC with method security. Opinionated starting point.security jwt
oauth2-resource-serverOAuth2 resource server config, JWT claim extraction, scope-based authorization.security oauth2

🤖 AI & MCP

SkillDescriptionTags
spring-ai-integrationSpring AI ChatClient, chat memory, RAG pipeline, structured output. Real GA artifact names — no dead pre-GA coordinates.spring-ai llm
mcp-serverBuild MCP servers with the Java SDK 2.x and Spring AI 2.0 native annotations. Tool registration, Streamable HTTP, and stdio safety.mcp ai-agents
ai-observabilityToken usage tracking, latency monitoring, prompt/response logging for Spring AI apps.observability spring-ai

📊 Operations

SkillDescriptionTags
production-observabilityActuator, Micrometer, OpenTelemetry/OTLP, health probes, structured logging, and actionable alerts.actuator micrometer opentelemetry

🧪 Testing

SkillDescriptionTags
testing-pyramidUnit → Slice → Integration conventions. @WebMvcTest, @DataJpaTest, @MockitoBean, Testcontainers.testing

⚡ Quick Start

1. Prepare your coding agent

Install Claude Code if needed:

npm install -g @anthropic-ai/claude-code

If you use Codex, confirm the CLI or desktop app command is available:

codex --version

2. Drop a skill into your project

Claude Code:

PROJECT_DIR=/path/to/my-spring-app
mkdir -p "$PROJECT_DIR/.claude/skills"
# Spring Boot 4 project
cp -r skills/spring-boot-4/rest-api-conventions "$PROJECT_DIR/.claude/skills/"
cp -r skills/spring-boot-4/spring-data-jpa "$PROJECT_DIR/.claude/skills/"

# Spring Boot 3 project — same skills, Boot 3 flavor
cp -r skills/spring-boot-3/rest-api-conventions "$PROJECT_DIR/.claude/skills/"

Codex:

PROJECT_DIR=/path/to/my-spring-app
mkdir -p "$PROJECT_DIR/.codex/skills"
# Spring Boot 4 project
cp -r skills/spring-boot-4/rest-api-conventions "$PROJECT_DIR/.codex/skills/"
cp -r skills/spring-boot-4/spring-data-jpa "$PROJECT_DIR/.codex/skills/"

# Spring Boot 3 project — same skills, Boot 3 flavor
cp -r skills/spring-boot-3/rest-api-conventions "$PROJECT_DIR/.codex/skills/"

Run these commands from the root of this repository, or replace skills/ with the path to your local clone.

For persistent project guidance, start from the matching templates:

# Codex, Spring Boot 4
cp templates/spring-boot-4/AGENTS.md "$PROJECT_DIR/AGENTS.md"

# Claude Code, Spring Boot 4
cp templates/spring-boot-4/CLAUDE.md "$PROJECT_DIR/CLAUDE.md"

Boot 3 equivalents live under templates/spring-boot-3/. Adapt commands and conventions to the project rather than using the templates unchanged.

Install from the Claude Code marketplace

This repository also exposes two marketplace plugins without duplicating the skill files:

claude plugin marketplace add rrezartprebreza/spring-boot-skills
claude plugin install spring-boot-4-skills@spring-boot-skills
# or for a Boot 3 project:
claude plugin install spring-boot-3-skills@spring-boot-skills

The marketplace manifest is .claude-plugin/marketplace.json. Validate it locally with claude plugin validate .. The repository can be submitted to Anthropic's Claude Code community marketplace; approval is a separate review step. GitHub Marketplace is intended for GitHub Apps and Actions, so this skills repository should use GitHub releases and the Claude marketplace instead.

Install as a Codex plugin

Codex uses its own plugin manifest and marketplace catalog. Add this repository and install the version that matches your application:

codex plugin marketplace add rrezartprebreza/spring-boot-skills
codex plugin add spring-boot-4-skills@spring-boot-skills
# or for a Boot 3 project:
codex plugin add spring-boot-3-skills@spring-boot-skills

The Codex package metadata lives in .agents/plugins/marketplace.json and the two plugin manifests under plugins/. Direct copying into .codex/skills/ remains supported for projects that do not use plugins.

3. Tell your agent what you want

claude
> Generate a CRUD endpoint for the Order entity following our REST conventions

or:

codex
> Generate a CRUD endpoint for the Order entity following our REST conventions

That's it. Your agent reads the skill before writing a single line.


⚔️ Before / After

The value of these skills is not generic Spring Boot advice. The value is preventing the small mistakes AI agents make when they do not know your backend conventions.

❌ Without a skill✅ With layered-architecture + rest-api-conventions
@RestController
public class OrderController {
    @Autowired
    private OrderRepository repository;

    @PostMapping("/orders")
    public ResponseEntity<?> create(
            @RequestBody Order order) {
        return ResponseEntity.ok(
            repository.save(order));
    }
}
@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
class OrderController {
    private final OrderService orderService;

    @PostMapping
    ResponseEntity<ApiResponse<OrderResponse>> create(
            @Valid @RequestBody CreateOrderRequest request) {
        OrderResponse response = orderService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(ApiResponse.ok(response));
    }
}
  • Business logic leaks into the controller
  • No request DTO or validation boundary
  • Repository called directly from the web layer
  • Response shape ignores project conventions
  • Status codes left to framework defaults
  • Controller as a pure HTTP adapter
  • Service owns the business rules
  • DTO validation at the boundary
  • Consistent response envelope
  • Correct 201 Created semantics

📐 Skill Anatomy

Every skill in this repo follows the same structure:

skills/spring-boot-4/rest-api-conventions/
├── SKILL.md          ← the skill: trigger description + conventions + gotchas
├── agents/
│   └── openai.yaml   ← Codex skill-list metadata and default prompt
├── examples/         ← good and bad examples, side by side
│   ├── good-controller.java
│   └── bad-controller.java
└── templates/        ← copy-paste starting points
    ├── ApiResponse.java
    └── GlobalExceptionHandler.java

SKILL.md has two critical parts:

---
name: rest-api-conventions
description: >
  Use when generating REST controllers, response objects, DTOs, or error handlers.
  Defines the project's response envelope, HTTP status mapping, and error code conventions.
---

## Conventions
...

The description is a trigger — write it as "use when [condition]", not as a summary. This is what makes the agent actually load the skill.

The Gotchas section at the bottom of each skill is the secret weapon: a running list of the exact mistakes agents make in that domain, phrased as Agent does X — do Y instead.


💡 Tips from the trenches

The Gotchas section is the most valuable part — add to it every time the agent does something wrong. Your future self will thank you.

Don't describe what Spring Boot already knows. Skills should push your agent out of its default behavior, not repeat the docs.

Be opinionated about your project. Generic Spring Boot best practices belong in a blog post. Skills belong in your agent skills folder.

Fork this repo and customize. Every team's conventions are different. These are starting points, not gospel.

Combine with CLAUDE.md or AGENTS.md. Project guidance stores build commands, verification, and architecture decisions. Skills provide reusable domain-specific workflows.

Anti-patternFix
Giant SKILL.md with everythingSplit into focused skills, one concern each
"Always use constructor injection"Already a strong agent default — skip it
No examplesAdd a good.java and bad.java — the contrast is what teaches
Prescriptive step-by-step instructionsGive goals and constraints, let agent decide how
Never updatingAdd a Gotchas section, update it when agent fails

🔥 Hot: MCP Server Skill

The mcp-server skill is the most powerful one here.

It teaches your agent to build production-ready MCP servers on MCP Java SDK 2.x and the Spring AI 2.0 starters - the same protocol used by Claude, Codex, Cursor, VS Code, and other major AI coding tools.

The MCP skill distinguishes native MCP annotations such as @McpTool from Spring AI model tool-calling annotations such as @Tool. Use the native MCP path when exposing server tools.

// What the agent generates with the skill loaded —
// real GA API: spring-ai-starter-mcp-server + annotation scanning
@Component
public class OrderMcpTools {

    private final OrderService orderService;

    @McpTool(name = "get_order",
             description = "Get a single order by ID including all line items and status history")
    public OrderResponse getOrder(
            @McpToolParam(description = "UUID of the order", required = true) String orderId) {
        return OrderResponse.from(orderService.findById(UUID.fromString(orderId)));
    }
}

Without the skill, the agent guesses: dead pre-GA artifact names, removed SDK constructors, @Tool instead of native @McpTool, or System.out logging that corrupts stdio transport.


🗺️ Roadmap

  • Skills for Spring Batch
  • Spring Boot 4 versions of all 33 skills (skills/spring-boot-4/)
  • Skills for Spring Cloud Gateway
  • Skills for Spring WebFlux / reactive patterns
  • Skills for multi-tenancy
  • Spring Boot 3 → 4 migration skill
  • Production observability skill
  • Event-driven messaging skill
  • Container and native deployment skill
  • CLAUDE.md and AGENTS.md templates for Boot 3 and Boot 4
  • /generate-endpoint command
  • /write-test command
  • /db-migrate command
  • Integration with Hatch background job library
  • Integration with SpringPulse observability

🤝 Contributing

Skills get better with real-world use. If you find a gap — the agent did something stupid in your Spring Boot project — open a PR and add it to the Gotchas section of the relevant skill.

Before opening a PR, install the validator dependency in a virtual environment and run:

python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r scripts/requirements.txt
bash scripts/validate-skills.sh

The validator parses YAML safely, rejects duplicate keys, and checks both version trees, metadata, README links and marketplace packaging. There are 33 topics with Boot 3 and Boot 4 variants.

Executable verification

The behavior fixture compiles the shipped JWT, Problem Details, pagination and configuration templates. Its tests cover token/account rejection, HTTP error contracts, configuration startup validation, and JPA/Flyway against PostgreSQL. CI runs Boot 3.5 and Boot 4.1 with Java 17 and 21. The MCP compilation fixture remains separate. This is targeted coverage, not a claim that every example in the catalog has executable tests.

Agent evaluations provide repeatable prompts and review criteria for Claude Code and Codex. Transcript collection and human review are separate from CI validation; a successful model invocation is not a benchmark pass.

1. Fork the repo
2. Copy an existing skill as a template
3. Fill in conventions, examples, gotchas
4. PR with a one-line description of what problem it solves

🛠️ More from the same workbench

RepoDescription
HatchMulti-module background job library for Spring Boot — REST polling, retry, Redis/JDBC backends, SSE dashboard
SpringPulseRuntime observability for @Scheduled methods — AOP interception, WebSocket dashboard
rest-api-generatorCLI that scaffolds Spring Boot REST APIs from plain English prompts

If a skill saved your agent from writing @Autowired field injection today — ⭐ star the repo.


spring-boot · java · claude-code · codex · mcp · spring-ai · skills · developer-tools


Built by @rrezartprebreza · Pristina, Kosovo


LinkedIn

Agent / MCP / Skill 创作

低风险

  • 来源需自行核对维护者身份。
  • 未检测到明显脚本安装指令。
  • 未检测到明显外部权限要求。
  • 未检测到高风险命令。
  • 扫描发现:0 条。

Codex — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/rrezartprebreza/spring-boot-skills.git
  3. 将 "skills/spring-boot-4/spring-batch" 文件夹复制到 Codex 的 skills 目录中。
  4. 重启 Codex 让新的 skill 生效。

Codex — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Codex 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Codex 让新的 skill 生效。

Claude Code — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/rrezartprebreza/spring-boot-skills.git
  3. 将 "skills/spring-boot-4/spring-batch" 文件夹复制到 Claude Code 的 skills 目录中。
  4. 重启 Claude Code 让新的 skill 生效。

Claude Code — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Claude Code 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Claude Code 让新的 skill 生效。

Cursor — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/rrezartprebreza/spring-boot-skills.git
  3. 将 "skills/spring-boot-4/spring-batch" 文件夹复制到 Cursor 的 skills 目录中。
  4. 重启 Cursor 让新的 skill 生效。

Cursor — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Cursor 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Cursor 让新的 skill 生效。

GitHub Copilot — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/rrezartprebreza/spring-boot-skills.git
  3. 将 "skills/spring-boot-4/spring-batch" 文件夹复制到 GitHub Copilot 的 skills 目录中。
  4. 重启 GitHub Copilot 让新的 skill 生效。

GitHub Copilot — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 GitHub Copilot 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 GitHub Copilot 让新的 skill 生效。

Windsurf — Git Clone 安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 克隆仓库:git clone https://github.com/rrezartprebreza/spring-boot-skills.git
  3. 将 "skills/spring-boot-4/spring-batch" 文件夹复制到 Windsurf 的 skills 目录中。
  4. 重启 Windsurf 让新的 skill 生效。

Windsurf — 手动复制安装

  1. 安装前请先查看来源仓库和风险报告。
  2. 从源仓库下载 SKILL.md 及相关文件。
  3. 在 Windsurf 的 skills 目录中创建新文件夹。
  4. 将所有 skill 文件复制到新文件夹中。
  5. 重启 Windsurf 让新的 skill 生效。
查看 SKILL.md 原文
name: spring-batch
description: >
  Use when building batch jobs, ETL pipelines, scheduled imports/exports, or any chunk-oriented
  bulk processing with Spring Batch. Covers the Spring Batch 6 / Boot 4 builder API, resourceless
  vs JDBC job repositories, restartability and idempotent job parameters, reader/writer
  thread-safety, fault tolerance, and chunk transaction boundaries.

Spring Batch

Spring Boot 4.x ships Spring Batch 6. The API changed significantly from 5.x (and drastically from 4.x) — most online examples are wrong. The rules that break the most agent-generated code:

  1. Do NOT add @EnableBatchProcessing. Boot auto-configures the JobRepository, JobOperator, and transaction manager. Adding @EnableBatchProcessing disables that auto-configuration and you lose all the wired beans.
  2. Metadata is in-memory by default. Batch 6's JobRepository is resourceless — nothing is persisted. Restartability and the BATCH_* audit tables require the spring-boot-starter-batch-jdbc starter (plain spring-boot-starter-batch = no restart after a crash).
  3. JobLauncher and JobExplorer are consolidated into JobOperator (which extends both). Inject JobOperator and call start(job, params).
  4. JobBuilderFactory/StepBuilderFactory are long gone, and chunk(500, txManager) is the old Batch 5 style — Batch 6 takes the size alone, with an optional .transactionManager(...).

Dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-batch-jdbc</artifactId> <!-- persistent BATCH_* metadata -->
</dependency>
<!-- spring-boot-starter-batch alone = resourceless in-memory repository:
     fine for run-and-forget jobs, but no restart-on-failure, no audit trail -->

Job & Step (Spring Batch 6 API)

@Configuration
@RequiredArgsConstructor
public class OrderExportJobConfig {

    @Bean
    public Job orderExportJob(JobRepository jobRepository, Step exportStep) {
        return new JobBuilder("orderExportJob", jobRepository)
            .incrementer(new RunIdIncrementer()) // lets the same job be re-run; see "Idempotency"
            .start(exportStep)
            .build();
    }

    @Bean
    public Step exportStep(JobRepository jobRepository,
                           PlatformTransactionManager txManager, // Boot's, injected — do NOT new one up
                           ItemReader<Order> reader,
                           ItemProcessor<Order, OrderRow> processor,
                           ItemWriter<OrderRow> writer) {
        return new StepBuilder("exportStep", jobRepository)
            .<Order, OrderRow>chunk(500)        // chunk size is the commit interval — and a TX boundary
            .transactionManager(txManager)      // optional in Batch 6 — but set it for JDBC-backed steps
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .faultTolerant()
            .skip(FlatFileParseException.class)
            .skipLimit(50)
            .build();
    }
}

chunk(500) means: read 500 items, process each, hand the list of 500 to the writer, commit one transaction, repeat. The chunk is the unit of restart and the unit of rollback. The Batch 5 form chunk(500, txManager) is deprecated — size and transaction manager are now separate builder calls.

Idempotency & Restartability — the #1 operational gotcha

A JobInstance is identified by its identifying JobParameters. Launch the same job with the same identifying parameters twice and you get:

JobInstanceAlreadyCompleteException: A job instance already exists and is complete

This is by design — Batch refuses to re-run completed work. Two ways to handle it:

// Option A — RunIdIncrementer on the job (above) + JobLauncherApplicationRunner bumps run.id each launch.
// Option B — add a unique identifying parameter yourself when launching:
JobParameters params = new JobParametersBuilder()
    .addString("status", "COMPLETED")              // identifying — part of the instance key
    .addLong("run.id", System.currentTimeMillis()) // identifying & unique — makes each run a new instance
    .toJobParameters();

Mark a parameter non-identifying with the false flag when it's metadata that shouldn't change the instance identity (e.g. a request id you log but don't key on):

.addString("requestId", requestId, false) // non-identifying — excluded from the instance key

(In Batch 6 JobParameter is an immutable record that carries its own name — JobParameters holds a Set<JobParameter> — but the builder above is unchanged.)

A failed job, by contrast, is resumed when relaunched with the same parameters — it skips completed steps and restarts the failed step from the last committed chunk. That is the point of the metadata tables — and it only works with the JDBC job repository; the default resourceless repository forgets everything when the JVM exits. Don't defeat it by always passing a unique parameter if you want resume-on-failure.

ItemReader — sort key and thread-safety

@Bean
@StepScope // required: late-binds jobParameters at step execution, not context startup
public JpaPagingItemReader<Order> orderReader(
        EntityManagerFactory emf,
        @Value("#{jobParameters['status']}") String status) {
    return new JpaPagingItemReaderBuilder<Order>()
        .name("orderReader")
        .entityManagerFactory(emf)
        .queryString("SELECT o FROM Order o WHERE o.status = :status ORDER BY o.id") // ORDER BY is MANDATORY
        .parameterValues(Map.of("status", OrderStatus.valueOf(status)))
        .pageSize(500) // keep pageSize == chunk size
        .build();
}
  • Paging readers require a deterministic ORDER BY on a unique column. Without it the DB returns rows in arbitrary order across pages → rows get skipped or processed twice. This is silent data corruption, not an error.
  • JdbcCursorItemReader is NOT thread-safe. JdbcPagingItemReader / JpaPagingItemReader are safe for multi-threaded steps. For a non-thread-safe reader in a multi-threaded step, wrap it in SynchronizedItemStreamReader.
  • Don't mutate the column you page on inside the same job. If the writer flips status from PENDING to DONE while the reader pages WHERE status = 'PENDING' ORDER BY id, the result set shifts under you and pages are missed. Read into a stable snapshot, page by immutable id, or use a cursor reader.

ItemProcessor — returning null filters

@Component
public class OrderProcessor implements ItemProcessor<Order, OrderRow> {
    @Override
    public OrderRow process(Order order) {
        if (order.getTotal().isZero()) {
            return null; // ⚠️ null = FILTER this item; it is NOT written and NOT an error
        }
        return OrderRow.from(order);
    }
}

Returning null silently drops the item from the chunk. That's a feature (filtering) but a footgun if you returned null by accident expecting it to pass through.

ItemWriter — Chunk, not List

Since Batch 5 the writer receives a Chunk<? extends T>, not List<? extends T>:

@Override
public void write(Chunk<? extends OrderRow> chunk) { // was List<? extends T> in 4.x
    repository.saveAll(chunk.getItems());
}

For SQL writes, prefer the batched JDBC writer over per-row saves — it uses one addBatch():

@Bean
public JdbcBatchItemWriter<OrderRow> orderWriter(DataSource dataSource) {
    return new JdbcBatchItemWriterBuilder<OrderRow>()
        .dataSource(dataSource)
        .sql("INSERT INTO order_export (id, total) VALUES (:id, :total)")
        .beanMapped()
        .build();
}

The writer runs inside the chunk transaction. Never fire emails, publish to Kafka, or call webhooks from a writer — if the chunk rolls back you've already sent it. Bind side effects to the job completion instead (see [[transactional-patterns]] and the listener below).

Launching jobs

Boot runs every Job bean on startup by default. For scheduled or on-demand jobs, turn that off and launch explicitly:

spring:
  batch:
    job:
      enabled: false           # don't run jobs on app startup; we trigger them ourselves
    jdbc:
      initialize-schema: never # (batch-jdbc starter) manage BATCH_* tables with Flyway in prod
@Component
@RequiredArgsConstructor
public class OrderExportScheduler {

    private final JobOperator jobOperator; // Batch 6: replaces JobLauncher AND JobExplorer
    private final Job orderExportJob;

    @Scheduled(cron = "0 0 2 * * *")
    public void runNightly() throws JobExecutionException {
        JobParameters params = new JobParametersBuilder()
            .addString("status", "COMPLETED")
            .addLong("run.id", System.currentTimeMillis())
            .toJobParameters();
        jobOperator.start(orderExportJob, params);
    }
}

Use start(Job, JobParameters) — the old start(String jobName, Properties) overload is deprecated for removal. The default JobOperator is synchronous — start(...) blocks the @Scheduled thread until the whole job finishes. For fire-and-forget, configure it with an async TaskExecutor (or annotate a @Bean method with @BatchTaskExecutor), or trigger from a request thread only if you accept the block.

Metadata schema in production

With the JDBC repository, Spring Batch needs its BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_STEP_EXECUTION, … tables. initialize-schema: always is fine for dev/embedded DBs but don't let Batch DDL your production database on startup. Set initialize-schema: never and ship the schema as a versioned [[flyway-migrations]] migration (the canonical DDL lives in org/springframework/batch/core/schema-*.sql inside spring-batch-core). Upgrading an existing Boot 3 database? Batch 6 renamed the BATCH_JOB_SEQ sequence to BATCH_JOB_INSTANCE_SEQ — the project ships migration scripts; add one to your Flyway history.

Listeners — work that must run after the job, not per chunk

@Bean
public Job orderExportJob(JobRepository jobRepository, Step exportStep) {
    return new JobBuilder("orderExportJob", jobRepository)
        .incrementer(new RunIdIncrementer())
        .listener(new JobExecutionListener() {
            @Override public void afterJob(JobExecution exec) {
                if (exec.getStatus() == BatchStatus.COMPLETED) {
                    notifier.notifyExportReady(exec.getJobParameters()); // safe: all chunks committed
                }
            }
        })
        .start(exportStep)
        .build();
}

Don't reach for Batch when you don't need it

Spring Batch earns its complexity (metadata tables, restart, chunking) on large, restartable, auditable bulk jobs. For a quick one-off async task, @Async or a @Scheduled loop is lighter. For durable background jobs with retry, a job queue is a better fit. Match the tool to the scale.

Gotchas

  • Agent adds @EnableBatchProcessing — on Boot it disables auto-config; remove it, just inject JobRepository
  • Agent uses plain spring-boot-starter-batch and expects restart/audit — Batch 6's default repository is resourceless (in-memory); use spring-boot-starter-batch-jdbc for the BATCH_* tables
  • Agent uses JobBuilderFactory / StepBuilderFactory — removed in Batch 5; use new JobBuilder(name, repo) / new StepBuilder(name, repo)
  • Agent calls .chunk(500, txManager) — Batch 5 style, deprecated in 6; use .chunk(500) + .transactionManager(txManager)
  • Agent injects JobLauncher or JobExplorer — consolidated into JobOperator in Batch 6; inject JobOperator and call start(job, params)
  • Agent calls jobOperator.start("jobName", properties) — deprecated for removal; use start(Job, JobParameters)
  • Agent writes manual config @EnableBatchProcessing(dataSourceRef = ...) — split in Batch 6: @EnableBatchProcessing(taskExecutorRef = ...) + @EnableJdbcJobRepository(dataSourceRef = ...)
  • Agent reuses a Boot 3 Flyway baseline for BATCH_* — Batch 6 renamed BATCH_JOB_SEQ to BATCH_JOB_INSTANCE_SEQ; add the migration script
  • Agent writes write(List<? extends T> items) — the signature is write(Chunk<? extends T> chunk) since Batch 5
  • Agent expects batch metrics to just appear — Batch 6 dropped Micrometer's global static registry; declare an ObservationRegistry bean wired to your MeterRegistry
  • Agent re-runs a job with identical parameters and hits JobInstanceAlreadyCompleteException — add RunIdIncrementer or a unique identifying param
  • Agent adds a unique param every run on a job that should resume-on-failure — kills restartability; only add it when you want a fresh instance
  • Agent writes a paging reader query with no ORDER BY (or a non-unique one) — pages skip/duplicate rows silently; order by a unique column
  • Agent uses JdbcCursorItemReader in a multi-threaded step — not thread-safe; use a paging reader or SynchronizedItemStreamReader
  • Agent pages on a column the writer mutates in the same job — result set shifts; page on an immutable id
  • Agent returns null from a processor expecting pass-through — null filters (drops) the item
  • Agent sends email / publishes events from the ItemWriter — runs inside the chunk TX; do it in an afterJob listener
  • Agent forgets @StepScope on a reader that reads jobParameters — @Value("#{jobParameters[...]}") only binds in step scope
  • Agent leaves jobs running on startup in a web app — set spring.batch.job.enabled=false and launch explicitly
  • Agent lets initialize-schema: always DDL the prod DB — use never + a Flyway migration for the BATCH_* tables

发现问题?提交给管理员复核

评分:

评论 (0)

暂无评论,成为第一个评论者吧!