我正在使用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,我可以清楚地看到我的代码似乎没有做到这一点
我有点迷失如何使这项工作。非常感谢任何帮助
答案 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 {}
}