Spring Batch生成ACH格式文件任务无法终止,持续循环写入
问题排查与优化方案
一、无限循环生成记录的排查方向
- ItemReader终止逻辑失效:Spring Batch的Step会持续调用
read()方法,直到返回null才会停止读取。检查你的Mock ItemReader是否在生成1条记录后,后续read()调用能正确返回null。如果Reader始终返回非null对象,Step会无限循环执行。 - Step提交与终止配置问题:确认Step的
commit-interval是否合理,即使设置chunk(1),核心还是依赖Reader返回null来触发Step结束。如果没有配置明确的终止条件(如限制读取次数),且Reader不终止,任务会持续运行。 - Bean作用域状态污染:如果ItemReader是单例Bean,内部的计数或状态变量可能在重复调用时无法重置,导致一直生成新记录。尝试将Reader标记为
@StepScope,确保每次Step执行时创建新实例,避免状态复用。 - Job终止条件缺失:检查Job是否配置了正确的结束触发逻辑,比如是否通过
JobParameters控制执行次数,或是否有JobExecutionListener强制终止,但这类情况较少见,优先排查Reader逻辑。
二、Spring Batch生成固定长度大型机风格记录的更优方式
1. 原生组件:FlatFileItemWriter + FormatterLineAggregator
Spring Batch自带的FlatFileItemWriter配合FormatterLineAggregator可以原生支持固定长度格式,无需手动拼接字符串:
@Bean public FlatFileItemWriter<AchRecord> achFileWriter() { FlatFileItemWriter<AchRecord> writer = new FlatFileItemWriter<>(); writer.setResource(new FileSystemResource("output.ach")); FormatterLineAggregator<AchRecord> lineAggregator = new FormatterLineAggregator<>(); // 按ACH规范定义固定长度格式:左对齐、补零、固定宽度等 lineAggregator.setFormat("%-1s%-9s%010d%-20s"); BeanWrapperFieldExtractor<AchRecord> fieldExtractor = new BeanWrapperFieldExtractor<>(); // 对应实体类字段顺序,与格式模板一一匹配 fieldExtractor.setNames(new String[]{"recordType", "batchId", "accountNumber", "payeeName"}); lineAggregator.setFieldExtractor(fieldExtractor); writer.setLineAggregator(lineAggregator); return writer; }
2. 自定义LineAggregator处理多类型记录
如果ACH文件包含多种记录类型(头记录、明细记录、尾记录),可自定义LineAggregator根据记录类型切换格式:
public class AchLineAggregator implements LineAggregator<AchRecord> { @Override public String aggregate(AchRecord item) { return switch (item.getRecordType()) { case "HEADER" -> String.format("%-1s%-10s%-8s", item.getRecordType(), item.getFileId(), item.getCreateDate()); case "DETAIL" -> String.format("%-1s%012d%-30s", item.getRecordType(), item.getAmount(), item.getMemo()); case "TRAILER" -> String.format("%-1s%06d%010d", item.getRecordType(), item.getTotalRecords(), item.getTotalAmount()); default -> throw new IllegalArgumentException("Unknown record type: " + item.getRecordType()); }; } }
随后在FlatFileItemWriter中设置该自定义聚合器即可。
3. 格式校验与异常处理
在ItemProcessor中添加固定长度校验逻辑,确保生成的记录完全符合ACH规范:
public class AchRecordProcessor implements ItemProcessor<AchRecord, AchRecord> { private static final int ACH_RECORD_LENGTH = 94; // ACH标准记录长度 @Override public AchRecord process(AchRecord item) throws Exception { String line = new AchLineAggregator().aggregate(item); if (line.length() != ACH_RECORD_LENGTH) { throw new InvalidRecordException("Record length invalid: " + line.length()); } return item; } }
4. 动态输出文件配置
通过@StepScope结合JobParameters实现每次运行生成不同的输出文件,避免文件覆盖:
@Bean @StepScope public FlatFileItemWriter<AchRecord> achFileWriter(@Value("#{jobParameters['outputFile']}") String outputFile) { FlatFileItemWriter<AchRecord> writer = new FlatFileItemWriter<>(); writer.setResource(new FileSystemResource(outputFile)); // 其他配置... return writer; }
内容的提问来源于stack exchange,提问作者Simeon Leyzerzon
相关产品推荐
相关产品推荐

