Spring Batch MultiResourceItemReader重新读取第一个资源

时间:2017-11-23 23:22:36

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

我正在使用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 {}
}

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

我还浏览了MultiResouceItemReader in Spring Batch的源代码,看起来,委托类的read方法应该在读取每个项目后返回null,我可以清楚地看到我的代码似乎没有做到这一点

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

2 个答案:

答案 0 :(得分:0)

MultiResourceItemReader每次都不返回null。如果没有更多资源要读取它会返回NULL,否则它会向委托返回下一个资源,这意味着 - 您的实际读者

我可以在read()方法中看到问题。你你没有转移到下一个文件。当您实施自己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的实施情况。你需要完全相同的方式

答案 1 :(得分:0)

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

@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 {}
}