Spring Batch自定义Item Writer无法写入ReportDetail文件问题
解决Spring Batch中自定义ItemWriter写入文件为空的问题
看起来你的ReportWriter已经能正确获取到Record数据(控制台能打印item.getCode()),但文件里没内容,核心问题出在PrintWriter的缓冲机制和资源关闭的时机上,我给你分析下并提供修复方案:
问题根源
- PrintWriter默认不自动刷新缓冲区:你当前的
PrintWriter是用默认构造创建的,写入的内容会先存在内存缓冲区里,不会立刻写到文件。只有当缓冲区满了、调用flush()或者close()时,才会把内容刷入文件。 - @PreDestroy的执行时机不确定:虽然你加了
@PreDestroy注解,但Spring Batch对ItemWriter的生命周期管理中,这个注解的触发时机可能晚于你预期,或者如果Bean没有被Spring正确管理的话,close()方法甚至不会被调用,导致缓冲区的内容永远没机会写入文件。
修复方案
方案一:启用PrintWriter自动刷新
修改ReportWriter的构造函数,创建PrintWriter时开启自动刷新功能(第二个参数传true),这样每次调用println()时都会自动刷新缓冲区,内容会立刻写入文件:
public ReportWriter() { OutputStream out; try { out = new FileOutputStream("ReportDetail.txt"); } catch (FileNotFoundException e) { System.out.println("Exception e" + e); out = System.out; } // 开启自动刷新 this.writer = new PrintWriter(out, true); }
方案二:实现ItemStream接口,利用Spring Batch的生命周期管理
Spring Batch推荐需要处理资源的ItemWriter实现ItemStream接口,这样可以在作业的正确阶段(比如步骤结束时)刷新和关闭资源,比@PreDestroy更可靠:
public class ReportWriter implements ItemWriter<Record>, ItemStream, Closeable { private PrintWriter writer = null; public ReportWriter() { OutputStream out; try { out = new FileOutputStream("ReportDetail.txt"); } catch (FileNotFoundException e) { System.out.println("Exception e" + e); out = System.out; } this.writer = new PrintWriter(out); } @Override public void write(final List<? extends Record> items) throws Exception { for (Record item : items) { System.out.println(item.getCode()); // 打印到控制台验证 writer.println(item.getCode()); } // 每次write后手动刷新缓冲区 writer.flush(); } @Override public void open(ExecutionContext executionContext) throws ItemStreamException { // 初始化资源(如果需要) } @Override public void update(ExecutionContext executionContext) throws ItemStreamException { // 可以在这里定期刷新,防止数据丢失 writer.flush(); } @Override public void close() throws IOException { writer.flush(); // 关闭前最后一次刷新 writer.close(); } }
额外注意点
- 你的构造函数里,当
FileNotFoundException发生时会把输出转到System.out,建议这里加上更明确的日志(比如用SLF4J代替System.out),避免文件创建失败了你却没察觉。 - 确保
ReportWriter是被Spring容器管理的Bean(比如用@Component注解,或者在Batch配置类中手动注册),否则@PreDestroy和ItemStream的方法都不会被正确调用。
内容的提问来源于stack exchange,提问作者AssenKhan
相关产品推荐
相关产品推荐

