【问题标题】:Spring Boot batch - MultiResourceItemReader : move to next file on errorSpring Boot批处理-MultiResourceItemReader:出错时移至下一个文件
【发布时间】:2016-01-11 11:10:33
【问题描述】:

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

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

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

有人知道怎么做吗?

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

【问题讨论】:

    标签: java spring-boot spring-batch


    【解决方案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@OnReadErrorinject MoveNextReader 的委托并设置MoveNextReader.skipThisFile

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

    【讨论】:

    • 谢谢!我现在关心的是找到一种方法来强制 MultiResourceItemReader 移动到下一个资源。就像我说的那样,它有一个 readNextItem 方法,但它是私有的。我觉得我必须复制和调整课程才能做到这一点。但我不想...
    • 有了一个监听器和一个类,你可以在没有'copy&adapt'的情况下隔离跳过逻辑
    • 好吧,在第一次阅读时我没有明白你的想法。您建议在 MultiResourceItemReader 和读取我的文件的真实委托之间放置一个“假”委托,该委托返回 null 以停止读取过程并强制 MultiResourceItemReader 跳转到下一个资源。我会尝试类似的东西!
    【解决方案2】:

    这是我的最终类,用于读取多个 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-09
      • 2015-10-27
      • 2021-08-31
      • 1970-01-01
      • 2018-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多