![](/img/trans.png)
[英]Spring Batch: MultiResourceItemReader with custom ItemReader reads the same file ad infinitum
[英]MultiResourceItemReader with a custom delegate keeps reading the same file
你好 java 向导,
我在进入 spring 批次时遇到了很多麻烦。 现在开门见山。 我需要处理一个文件夹中的所有文件(xmls),然后它们将它们写回,并添加少量内容。 问题是我想保留输入文件名。 我对此的解决方案是一个 MultiResourceItemReader,它委托给一个自定义 Itemreader,后者又调用 StaxEventItemReader 并返回一个包含编组的 xml 和文件名的自定义项。
问题:在无限循环中只读取同一个文件,还有一件奇怪的事情,每次重试 10 次。 我知道一种解决方案是读取器在读取文件后返回 null,但这意味着我需要保留已处理文件的列表?
我想我现在会这样做,但我真的想要更聪明的东西。
作业配置:
<batch:job id="job1">
<batch:step id="step1" >
<batch:tasklet transaction-manager="transactionManager" start-limit="100" >
<batch:chunk reader="reader" writer="writer" commit-interval="10" />
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="reader" class="org.springframework.batch.item.file.MultiResourceItemReader">
<property name="resources" value="files/*.xml" />
<property name="delegate" ref="myItemReader" />
</bean>
我的项目阅读方法,基本上:
public class MyItemReader implements ResourceAwareItemReaderItemStream<MyItem>, ApplicationContextAware {
public MyItem read() throws Exception, UnexpectedInputException,
ParseException, NonTransientResourceException {
StaxEventItemReader<JAXBElement<RootObject>> reader = new StaxEventItemReader<JAXBElement<RootObject>>();
reader.setResource(currentResource);
reader.setFragmentRootElementName("RootObject");
// ... create jaxb unmarshaller
reader.setUnmarshaller(unmarshaller);
reader.setSaveState(true);
reader.afterPropertiesSet();
reader.open(executionContext);
JAXBElement<RootObject> jaxbElem = reader.read();
MyItem item = new MyItem();
item.setFilename(currentResource.getFile().getName());
item.setJaxbElement(jaxbElem);
return item;
}
}
任何人都可以在这里理顺我吗?
解决方案所以最后我只保留一个已读文件列表,如果已读则返回 null。 至于一次读取 10 次,嗯,这是块的大小,所以这是有道理的。
我认为您不想在自定义阅读器中创建新阅读器。 我不知道它是否会导致您的问题,但这似乎不对(而且您在阅读后没有关闭它)。
您可以使用 Spring 初始化您的 JAXB 上下文,然后将其注入您的自定义阅读器:
http://static.springsource.org/spring-ws/site/reference/html/oxm.html
例子:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myItemReader" class="com.example.MyItemReader">
<property name="unmarshaller" ref="jaxbMarshaller"/>
</bean>
<oxm:jaxb2-marshaller id="jaxbMarshaller">
<oxm:class-to-be-bound
name="com.example.RootObject" />
</oxm:jaxb2-marshaller>
</beans>
然后在您的读者的read()
方法中,只需使用解组器...
public MyItem read() throws Exception, UnexpectedInputException,
ParseException, NonTransientResourceException {
Source source = new StreamSource(resource);
JAXBElement<RootObject> jaxbElem = unmarshaller.unmarshal(source);
MyItem item = new MyItem();
item.setFilename(resource.getFile().getName());
item.setJaxbElement(jaxbElem);
return item;
}
编辑
好的,我认为问题出在read()
方法上。 根据ItemReader的 Javadoc,当阅读器中的所有项目都用尽时, read()
方法应该返回 null ......我不认为你正在这样做,所以它会无限期地阅读。
我认为找到一种方法来扩展FlatFileItemReader
或StaxEventItemReader
是一种更好的方法......这样的事情不会奏效吗?
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<batch:job id="job1">
<batch:step id="step1" >
<batch:tasklet transaction-manager="transactionManager" start-limit="100" >
<batch:chunk reader="reader" writer="writer" commit-interval="10" />
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="reader" class="org.springframework.batch.item.file.MultiResourceItemReader">
<property name="resources" value="files/*.xml" />
<property name="delegate" ref="myItemReader" />
</bean>
<bean id="myItemReader" class="com.example.MyItemReader">
<property name="unmarshaller" ref="jaxbMarshaller"/>
<property name="fragmentRootElementName" ref="RootObject"/>
</bean>
<oxm:jaxb2-marshaller id="jaxbMarshaller">
<oxm:class-to-be-bound
name="com.example.RootObject" />
</oxm:jaxb2-marshaller>
</beans>
读者:
public class MyItemReader<T> extends StaxEventItemReader<T>{
private Resource resource;
@Override
public void setResource(Resource resource) {
this.resource = resource;
}
@Override
protected T doRead() throws Exception {
T jaxbElem = (T) super.doRead();
MyItem item = new MyItem();
item.setFilename(resource.getFile().getName());
item.setJaxbElement(jaxbElem);
return (T) item;
}
}
当你完全阅读完文件后,有必要让 spring 知道。 为此,您需要返回 null。
保留一个布尔标志以指示文件是否已处理。 如果处理返回null。 并再次将标志设置为 false。
boolean isRead=false;
MyItem read(){
if(isRead){
isRead=false;
return null;
}
MyItem item=null;
if(!isRead){
isRead=true;
//DO read.
item=new Item();// Item to read....
}
return item;
}
试试这个,覆盖 doOpen() 方法:
多资源项目阅读器:
@Component
public class CustomMultiResourceItemReader extends MultiResourceItemReader<Item> {
public CustomMultiResourceItemReader(CustomStaxItemReader customStaxItemReader) {
setName("customMultiResourceItemReader");
setResources(getResources());
setDelegate(customStaxItemReader);
}
}
StaxEventItemReader:
@Component
public class CustomStaxItemReader extends StaxEventItemReader<Item> {
private Resource resource;
public CustomStaxItemReader(){
setName("customStaxItemReader");
setFragmentRootElementName("YourFragmentRootElementName");
setUnmarshaller(getJaxb2Marshaller());
}
@Override
protected void doOpen() throws Exception {
super.setResource(resource);
super.doOpen();
}
@Override
protected Item read() throws Exception {
Item item = super.read();
if (item != null) item.setFileName(resource.getFile().getName());
return item;
}
@Override
public void setResource(Resource resource) {
this.resource = resource;
}
}
否则(不好的做法),使用反射读取父 class 的 'resource' 属性
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.