
本文详解 Spring Batch 中 ItemProcessor 不应维护跨 chunk 的状态,而应专注于单条记录转换;ItemWriter 通过 Chunk 自动接收当前批次的全部处理结果,无需在处理器中手动聚合列表。
本文详解 spring batch 中 `itemprocessor` 不应维护跨 chunk 的状态,而应专注于单条记录转换;`itemwriter` 通过 `chunk` 自动接收当前批次的全部处理结果,无需在处理器中手动聚合列表。
在 Spring Batch 的典型 chunk-oriented 处理流程中,数据流严格遵循 Reader → Processor → Writer 的职责分离原则。其中,ItemProcessor 的核心契约是:对单个输入项(InputObject)执行转换、增强或校验,并返回单个输出项(ProcessedObject)。它不应持有任何实例变量来累积或缓存多个 item 的状态——尤其不能使用类级别 List
你当前的实现存在两个关键问题:
-
违反处理器语义:process(InputObject) 方法签名表明其输入/输出均为单 item,但你却返回 List
,导致 Spring Batch 将整个 List 视为一个逻辑 item,最终传入 ItemWriter 的 Chunk 变为 Chunk - >,而非预期的 Chunk
; - 状态污染:processedList 是类成员变量,在多线程或多次 chunk 执行中持续累积,造成前一批次数据“泄漏”至后续 writer 调用,严重破坏数据隔离性与可重现性。
✅ 正确做法是让 ItemProcessor 回归单一职责:
@Override
public ProcessedObject process(InputObject input) throws Exception {
ProcessedObject o = new ProcessedObject();
try {
// ✅ 正确:仅基于当前 input 构建并填充 o
o.setId(input.getId());
o.setProcessedTime(Instant.now());
o.setBusinessResult(calculateResult(input));
} catch (Exception ex) {
o.setErrorFlag(true);
o.setErrorMessage(ex.getMessage());
}
return o; // ← 始终返回单个对象
}此时,你的 Step 配置也需同步调整,移除泛型中的 List
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory,
ItemProcessor<InputObject, ProcessedObject> myProcessor,
ItemWriter<ProcessedObject> myWriter) {
return stepBuilderFactory.get("step1")
.<InputObject, ProcessedObject>chunk(15) // ← 泛型明确:输入 InputObject,输出 ProcessedObject
.reader(myReader())
.processor(myProcessor)
.writer(myWriter)
.build();
}在 ItemWriter 中,你将自然接收到类型为 List
@Override
public void write(Chunk<? extends ProcessedObject> chunk) throws Exception {
List<ProcessedObject> items = chunk.getItems(); // ← 这就是本 chunk 的全部处理结果
// 按 error flag 分组写入
List<ProcessedObject> successes = items.stream()
.filter(o -> !o.isErrorFlag())
.collect(Collectors.toList());
List<ProcessedObject> failures = items.stream()
.filter(ProcessedObject::isErrorFlag)
.collect(Collectors.toList());
writeSuccessFile(successes);
writeErrorFile(failures);
}⚠️ 重要注意事项:
- ItemProcessor 必须是无状态(stateless)或作用域受限(如 @StepScope) 的 Bean;若需临时上下文(如计数器、缓存),应使用 StepExecution 属性或 @StepScope + @Value 注入运行时参数;
- 切勿在 processor 中操作共享集合、静态变量或外部存储,否则将引发并发安全问题与 chunk 边界失效;
- 若业务逻辑确需“批内关联处理”(如计算 batch 内统计值),应将该逻辑下沉至 ItemWriter 或自定义 ChunkListener,而非污染 processor。
总结:Spring Batch 的 chunk 机制已为你封装了批量聚合逻辑。信任框架,聚焦单一职责——processor 负责“转化每一条”,writer 负责“处理整一批”。这是保障批处理健壮性、可测试性与可扩展性的基石设计。










