【问题标题】:Spring Batch MultiResourceItemReader re-reading first resourceSpring Batch MultiResourceItemReader 重新读取第一个资源
【发布时间】:2017-11-23 23:22:36
【问题描述】:

我正在使用 Spring Boot 1.5 编写一个 Spring Batch 应用程序,以下是我的类:-

CustomMultiResourceItemReader.java

@StepScoped
@Component
public class CustomMultiResourceItemReader
        extends MultiResourceItemReader<MyDTO> {

    public MultiResourceXmlItemReader(
            @NonNull final MyResourceAwareItemReader itemReader,
            @NonNull final ApplicationContext ctx)
            throws IOException {
        setResources(
                ctx.getResources(
                        String.format(
                                "file:%s/*.xml", "~/data"))); // gives me a Resource[] array fine
        setDelegate(itemReader);
    }

    @PreDestroy
    void destroy() {
        close();
    }
}

MyResourceAwareItemReader.java

@RequiredArgsConstructor
@StepScope
@Component
@Slf4j
public class MyResourceAwareItemReader
        implements ResourceAwareItemReaderItemStream<MyDTO> {
    private static final String RESOURCE_NAME_KEY = "RESOURCE_NAME_KEY";
    @NonNull private final Unmarshaller unmarshaller; // JaxB Unmarshaller
    private Resource resource;

    @Override
    public void setResource(Resource resource) {
        this.resource = resource; // **gets called only once**
    }

    @Override
    public MyDTO read() throws Exception {
        final MyDTO dto = (MyDTO) unmarshaller.unmarshal(resource.getFile()); // Standard JaxB unmarshalling.
        return dto;
    }

    @Override
    public void open(ExecutionContext executionContext) throws ItemStreamException {
        if (executionContext.containsKey(RESOURCE_NAME_KEY)) {

        } else if (resource != null) {
            executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
        }
    }

    @Override
    public void update(ExecutionContext executionContext) throws ItemStreamException {
        if (resource != null) executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
    }

    @Override
    public void close() throws ItemStreamException {}
}

问题是delegate阅读器(MyResourceAwareItemReader.java)中的setResource方法在开始时只被调用一次;虽然 read 方法被多次调用,结果我多次读取同一个项目,而不是按预期读取下一个项目。

我也浏览了MultiResouceItemReader in Spring Batch的源代码,好像是委托类的read方法应该是在读取每一项后返回null,我可以清楚地看到我的代码似乎没有这样做。

我有点迷失了如何使这项工作。非常感谢任何帮助

【问题讨论】:

    标签: spring spring-boot spring-batch batch-processing


    【解决方案1】:

    进一步查看ItemReader 文档,清楚地详细说明了读者必须在输入数据集的末尾返回null。所以基本上我用boolean 标志实现了我的ItemReader,如下所示:-

    @RequiredArgsConstructor
    @StepScope
    @Component
    @Slf4j
    public class MyResourceAwareItemReader
            implements ResourceAwareItemReaderItemStream<MyDTO> {
        private static final String RESOURCE_NAME_KEY = "RESOURCE_NAME_KEY";
        @NonNull private final Unmarshaller unmarshaller; // JaxB Unmarshaller
        private Resource resource;
        private boolean isResourceRead;
    
        @Override
        public void setResource(Resource resource) {
            this.resource = resource;
            isResourceRead = false;
        }
    
        @Override
        public MyDTO read() throws Exception {
            if(isResourceRead == true) return null;
    
            final MyDTO dto = (MyDTO) unmarshaller.unmarshal(resource.getFile());
            isResourceRead = true;
            return dto;
        }
    
        @Override
        public void open(ExecutionContext executionContext) throws ItemStreamException {
            if (executionContext.containsKey(RESOURCE_NAME_KEY)) {
    
            } else if (resource != null) {
                executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
            }
        }
    
        @Override
        public void update(ExecutionContext executionContext) throws ItemStreamException {
            if (resource != null) executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
        }
    
        @Override
        public void close() throws ItemStreamException {}
    }
    

    【讨论】:

    • 在任何阅读器中返回null失败总是会导致循环;是的
    【解决方案2】:

    MultiResourceItemReader 不会每次都返回 null。如果没有更多资源可以读取,则返回 NULL,否则将下一个资源返回给委托,这意味着 – 您的实际阅读器

    我可以在您的 read() 方法中看到问题。 y你没有移动到下一个文件。在您实施时,您拥有自己的 MultiResourceItemReader 您有责任移至下一个资源项。

    这就是它被植入MultiResourceItemReader 的方式。您将需要自己的类似实现。

    private T readNextItem() throws Exception {
    
            T item = delegate.read();
    
            while (item == null) {
    
                currentResource++;
    
                if (currentResource >= resources.length) {
                    return null;
                }
    
                delegate.close();
                delegate.setResource(resources[currentResource]);
                delegate.open(new ExecutionContext());
    
                item = delegate.read();
            }
    
            return item;
        }
    

    您需要维护资源数组的索引。请检查MultiResourceItemReader 的实现。你需要做完全类似的方式

    【讨论】:

    • 没有实现我自己的MultiResourceItemReader;我只是在构造函数中设置了 2 个属性。我确实实现了自己的ResourceAwareItemStreamReader,并在其读取方法中读取并返回资源。但是如果你从 Spring 批处理中看到 MultiResourceItemReader.java 的代码,它会在委托的读取方法返回 null 时增加 Resource[] 索引。
    猜你喜欢
    • 1970-01-01
    • 2014-09-09
    • 2016-07-10
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    相关资源
    最近更新 更多