我可以帮助你解决我个人非常简单的错误。
我有一个非常基本的测试Spring Batch作业。它利用FlatFileItemReader从文件中读取并使用FlatFileItemWriter进行写入。如果项目的id以a结尾,则自定义处理器会抛出自定义SkipObjectException。 skip侦听器捕获SkipObjectException并使用FlatFileItemWriter将消息(字符串)写入文件。
重新启动时,取决于它何时失败,我得到一个ItemStreamException:当前文件大小小于上次提交时的大小。跳过文件发生此异常。如果我不在skip listener中写入文件,一切正常。
输入文件内容 001;第一条记录 002;第二记录 003;第三条记录 003a;首先跳过记录 004;第四条记录 005;第五条记录 006;第六条记录 007;第七条记录 007a;第二次跳过记录 008;第八条记录 009;第九条记录 010;第十条记录 011;第十一条记录 012;第十二条记录
成功测试 工作顺利。它将12条记录(除了003a和007a之外的所有记录)写入输出文件,并将两条记录(003a和007a)写入跳过的文件。大。
失败测试1 - 提交间隔为5并且处理器在项目004上失败。正如预期的那样,作业失败,输出文件和跳过文件都为空;这是有意义的,因为异常发生在提交间隔之前。
重新启动失败测试1 - 与上述相同但从处理器中删除异常。重新启动作业,它按预期运行,输出与成功测试相同。
失败测试2 - commit-interval为5;使项目004处理器失败。与以前相同的结果。
重新启动失败测试2 - commit-interval为5;使项目008上的处理器失败。作业重新启动然后在预期的位置失败。输出文件有4条记录(001到004除了003a),跳过文件有一条记录003a。因此,输出符合预期。
重新启动失败测试2 - commit-interval为5;从处理器中删除异常。除了ItemStreamException之外,作业无法重新启动:当前文件大小小于上次提交时的大小。跳过文件会发生此异常。
故障测试3 - 将commit-interval设置为10并使处理器在项目012上失败。作业在最后一项上按预期失败。除003a和007a外,输出文件包含项目001到008。跳过文件包含003a和007a。一切都好。
重新启动失败测试3 - 将commit-interval设置为10并从处理器中删除异常。当我重新启动作业时,我得到ItemStreamException:当前文件大小小于上次提交时的大小。这发生在跳过输出文件中。
调试信息 我在调试中执行失败测试3。在重新启动之后,在跳过文件的FlatFileItemWriter中,它认为当应该只有2时,会写入8条记录。
我尝试使用注释实现SkipListener,扩展SkipListenerSupport,实现ItemStream,所有这些都具有相同的结果。是的,我可以使用记录器(例如log4j)来编写它,但我想弄清楚我在实现FlatFileItemWriter时做错了什么。
就像我之前所说的那样,这很简单,但是下面是代码的重要部分 Job.xml
<batch:step id="step1">
<batch:tasklet allow-start-if-complete="false">
<batch:chunk reader="fileReader" processor="fileProcessor"
writer="fileWriter" commit-interval="5" skip-limit="10">
<batch:skippable-exception-classes>
<batch:include
class="com.myexception.SkipObjectException" />
</batch:skippable-exception-classes>
<batch:streams>
<batch:stream ref="skipListenerWriter" />
</batch:streams>
</batch:chunk>
<batch:listeners>
<batch:listener ref="customSkipListener" />
</batch:listeners>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="fileReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file:TestFiles/input/input.txt" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value=";" />
</bean>
</property>
<property name="fieldSetMapper" ref="fileMapper" />
</bean>
</property>
</bean>
<bean id="fileWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:TestFiles/output/output.txt" />
<property name="shouldDeleteIfExists" value="true" />
<property name="lineAggregator">
<bean
class="org.springframework.batch.item.file.transform.PassThroughLineAggregator" />
</property>
</bean>
<bean id="skipListenerWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:TestFiles/output/skipListener.txt" />
<property name="shouldDeleteIfExists" value="true" />
<property name="lineAggregator">
<bean
class="org.springframework.batch.item.file.transform.PassThroughLineAggregator" />
</property>
</bean>
处理器 - 如果正在处理的项目的id以a结尾,则抛出SkipObjectException。
CustomSkipListener
@Autowired
private FlatFileItemWriter<String> skipListenerWriter;
@OnSkipInProcess
public void processLog(FileObject theItem, Throwable theException) {
String myMessage = "Process skipped item: " + theException.getMessage()
+ " item: " + theItem.getNumber();
List<String> theItems = new ArrayList<String>();
theItems.add(myMessage);
logger.fatal(myMessage);
try {
this.skipListenerWriter.write(theItems);
} catch (Exception e) {
// TODO wouldn't actually do this...
throw new RuntimeException(e);
}
}
答案 0 :(得分:2)
我的解决方案,无论是对还是错,都是使用FlatFileItemWriter扩展的ItemStreamSupport抽象类中的name属性来唯一地命名编写器。
Spring Batch将写入文件的数量存储在name.written键下的执行上下文中。 FlatFileItemWriter的默认名称是FlatFileItemWriter。由于我有两个FlatFileItemWriters,因此只有一个项写入执行上下文(FlatFileItemWriter.written)。由于一个文件写入的文件多于重新启动时发生的其他损坏。唯一命名的作者解决了这个问题。如果有更合适的方法来处理这个问题,我将不胜感激。