Spring Boot批处理 - MultiResourceItemReader:出错时移动到下一个文件

时间:2015-10-13 15:47:19

标签: java spring-boot spring-batch

在批处理服务中,我使用MultiResourceItemReader读取多个XML文件,该文件委托给StaxEventItemReader。

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

目前,当引发读取异常时,批处理停止。

有没有人知道该怎么做?

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

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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-in-the-middle:

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;
    }
}