java 具有自定义委托的MultiResourceItemReader不断阅读同一文件

wswtfjt7  于 2023-01-29  发布在  Java
关注(0)|答案(3)|浏览(168)

你们好,java向导们,
我在进入 Spring 批处理时遇到了很多麻烦。现在直奔主题。我需要处理所有文件(xmls),然后他们将它们写回,有一个小的补充。问题是我想保留输入文件名。我对此的解决方案是一个MultiResourceItemReader,它委托给一个自定义ItemReader,该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个文件,嗯,这是块的大小,所以它是有意义的。
hs1ihplo

hs1ihplo1#

我不认为你想在你的自定义阅读器中创建一个新的阅读器。我不知道这是否导致了你的问题,但这似乎不对(而且你在阅读后没有关闭它)。
您可以使用Spring初始化JAXB Context,然后将其注入到自定义读取器中:
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 ......我不认为你这样做了,所以它是在无限期地读取。
我认为找到一种扩展FlatFileItemReaderStaxEventItemReader的方法是更好的方法...像这样的东西会不起作用吗?

<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;
    }

}
xj3cbfub

xj3cbfub2#

有必要让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;
}
xienkqul

xienkqul3#

尝试覆盖doOpen()方法:
多资源项目读取器:

@Component
public class CustomMultiResourceItemReader extends MultiResourceItemReader<Item> {
    public CustomMultiResourceItemReader(CustomStaxItemReader customStaxItemReader) {
        setName("customMultiResourceItemReader");
        setResources(getResources());
        setDelegate(customStaxItemReader);
    }
}

钉仓事件项目读取器:

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

否则(不好的做法),使用反射读取父类的“resource”属性

相关问题