2015-10-13 51 views
0

在批处理服务中,我使用MultiResourceItemReader读取多个XML文件,该文件委托给StaxEventItemReader。Spring Boot批处理 - MultiResourceItemReader:错误地移动到下一个文件

如果读取文件时出现错误(例如解析异常),我想指定Spring开始读取下一个匹配文件。例如,使用@OnReadError注释和/或SkipPolicy。

当前,当发生读取异常时,该批停止。

有没有人有一个想法如何做到这一点?

编辑:我看到MultiResourceItemReader有一个方法readNextItem(),但是它是私有-_-

回答

1

我不使用SB了一段时间,但看着MultiResourceItemReader代码,我想你可以写自己的ResourceAwareItemReaderItemStream包装,其中您检查设置为移动到下一个文件的标志或使用委托执行标准读取。
该标志可以存储到执行上下文中或包装中,并应在下一次移动后清除。

class MoveNextReader<T> implements ResourceAwareItemReaderItemStream<T> { 
    private ResourceAwareItemReaderItemStream delegate; 
    private boolean skipThisFile = false; 

    public void setSkipThisFile(boolean value) { 
    skipThisFile = value; 
    } 

    public void setResource(Resource resource) { 
    skipThisFile = false; 
    delegate.setResource(resource); 
    } 

    public T read() { 
    if(skipThisFile) { 
     skipThisFile = false; 
     // This force MultiResourceItemReader to move to next resource 
     return null; 
    } 
    return delegate.read(); 
    } 
} 

使用这个类的委托MultiResourceItemReader@OnReadError注入MoveNextReader并设置MoveNextReader.skipThisFile

我无法测试自己的代码,但我希望这可以是一个很好的起点。

+0

谢谢!我目前所关心的是找到一种方法来强制MultiResourceItemReader转移到下一个资源。就像我说的,它有一个方法readNextItem,但它是私人的。我觉得我将不得不复制和调整课程。但我不喜欢... – Eria

+0

有了一个听众和一个班级,你可以隔离跳过逻辑,而不需要'复制和修改' –

+1

好的,我在第一次阅读时没有得到你想到的。 您建议在MultiResourceItemReader和读取我的文件的实际委托之间放置一个“假”委托,它返回null以停止读取过程并强制MultiResourceItemReader跳转到下一个资源。我会尝试这样的事情! – Eria

0

这是我的最后一课,读取多个XML文件并在发生读取错误时跳转到下一个文件(感谢Luca的想法)。

我定制ItemReader,从MultiResourceItemReader扩展:

public class MyItemReader extends MultiResourceItemReader<InputElement> { 

    private SkippableResourceItemReader<InputElement> reader; 

    public MyItemReader() throws IOException { 
     super(); 

     // Resources 
     PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); 
     this.setResources(resourceResolver.getResources("classpath:input/inputFile*.xml")); 

     // Delegate reader 
     reader = new SkippableResourceItemReader<InputElement>(); 
     StaxEventItemReader<InputElement> delegateReader = new StaxEventItemReader<InputElement>(); 
     delegateReader.setFragmentRootElementName("inputElement"); 
     Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller(); 
     unmarshaller.setClassesToBeBound(InputElement.class); 
     delegateReader.setUnmarshaller(unmarshaller); 
     reader.setDelegate(delegateReader); 

     this.setDelegate(reader); 
    } 

    [...] 

    @OnReadError 
    public void onReadError(Exception exception){ 
     reader.setSkipResource(true); 
    } 
} 

,并用于跳过当前资源ItemReader,在中间人:

public class SkippableResourceItemReader<T> implements ResourceAwareItemReaderItemStream<T> { 

    private ResourceAwareItemReaderItemStream<T> delegate; 
    private boolean skipResource = false; 

    @Override 
    public void close() throws ItemStreamException { 
     delegate.close(); 
    } 

    @Override 
    public T read() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception { 
     if(skipResource){ 
      skipResource = false; 
      return null; 
     } 
     return delegate.read(); 
    } 

    @Override 
    public void setResource(Resource resource) { 
     skipResource = false; 
     delegate.setResource(resource); 
    } 

    @Override 
    public void open(ExecutionContext executionContext) throws ItemStreamException { 
     delegate.open(executionContext); 
    } 

    @Override 
    public void update(ExecutionContext executionContext) throws ItemStreamException { 
     delegate.update(executionContext); 
    } 

    public void setDelegate(ResourceAwareItemReaderItemStream<T> delegate) { 
     this.delegate = delegate; 
    } 

    public void setSkipResource(boolean skipResource) { 
     this.skipResource = skipResource; 
    } 
}