2

我正在使用 Spring Batch 设置将处理可能非常大的 XML 文件的作业。我想我已经正确设置了它,但是在运行时我发现作业运行,处理它的输入,然后只是挂在执行状态(我可以通过查看 JobRepository 中的 JobExecution 状态来确认)。

我已经多次阅读 Batch 文档,但没有看到任何明显的“输入不足时停止作业”配置。

这是我的应用程序上下文的相关部分:

<batch:job id="processPartnerUploads" restartable="true">
    <batch:step id="processStuffHoldings">
        <batch:tasklet>
            <batch:chunk reader="stuffReader" writer="stuffWriter" commit-interval="1"/>
        </batch:tasklet>        
    </batch:step>
</batch:job>

<bean id="stuffReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
  <property name="fragmentRootElementName" value="stuff" />
  <property name="resource" value="file:///path/to/file.xml" />
  <property name="unmarshaller" ref="stuffUnmarshaller" />
</bean>

<bean id="stuffUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="contextPath" value="com.company.project.xmlcontext"/>
</bean>

<bean id="stuffWriter" class="com.company.project.batch.StuffWriter" />

万一这很重要,“StuffWriter”只是一个记录将要写入的项目的类。

如果我错过了与 Batch 和/或 Stax 相关的一些重要细微差别,请告诉我。

4

1 回答 1

2

我已经为自己解决了这个问题,尽管我对自己必须做的事情感到惊讶。通过 StaxEventItemReader 进行调试,我注意到 moveCursorToNextFragment() 方法中的内部循环在到达文档末尾时会无限循环。以下是相关代码:

while (true) {
    while (reader.peek() != null && !reader.peek().isStartElement()) {
        reader.nextEvent();
    }
    if (reader.peek() == null) {
        return false;
    }
    QName startElementName = ((StartElement) reader.peek()).getName();
    if (startElementName.getLocalPart().equals(fragmentRootElementName)) {
        if (fragmentRootElementNameSpace == null
    || startElementName.getNamespaceURI().equals(fragmentRootElementNameSpace)) {
           return true;
        }
     }
    reader.nextEvent();
 }

reader.peek() 从未返回 null。在我看来,这段代码应该检查 peek() 期间遇到的 XMLEvent 是否位于文档末尾,但这并不是那么简单,因为 StaxEventItemReader 依赖于包装标准 XMLEventReader 的 DefaultFragmentEventReader。

我最终做的是基于 StaxEventItemReader 滚动我自己的 ItemReader 但根本不使用 FragmentEventReader,然后将内部循环代码调整为如下所示:

        if (reader.peek().getEventType() == XMLStreamConstants.END_DOCUMENT) {
            return false;
        }
        reader.nextEvent();

这完美地工作,并允许我的批处理作业在输入结束时进入 COMPLETED。

不过,我真的很惊讶我必须这样做。我想知道我使用的流式 XML 库的底层实现是否有问题,但我使用的是 Spring Batch 依赖项列表中引用的 stax2-api-3.0.1.jar。

我也发现我并不孤单

于 2011-10-18T20:21:09.790 回答