Spring Batch-How to process multiple records at the same time in the processor?

风流意气都作罢 提交于 2019-11-29 16:21:42

If you know the associated data records will be next to one another in the file (as opposed to spread out randomly), you can leverage the SingleItemPeekableItemReader to associate multiple lines to create one complete object. This older answer has a bit more info.

Example Context File:

<bean id="peekingReader" class="com.package.whatever.YourPeekingReader">
    <property name="delegate" ref="flatFileItemReader"/>
</bean>

<bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="file://temp/file.txt" />
    <property name="lineMapper">
        <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
            <property name="lineTokenizer" ref="yourTokenizer"/>
            <property name="fieldSetMapper" ref="yourMapper"/>
        </bean>
    </property>
</bean>

Example Peeking Reader:

public class YourPeekingReader extends SingleItemPeekableItemReader<YourObject> {

    @Override
    public YourObject read() {

        YourObject item = super.read();

        if (item == null) {
            return null;
        }

        while (true) {
            YourObject possibleRelatedObject = peek();
            if (possibleRelatedObject == null) {
                return item;
            }

            //logic to determine if next line in file relates to same object
            boolean matches = false; 

            if (matches) {
                item.addRelatedInfo(super.read());
            } else {
                return item;
            }
        }


    }

}

@Dean..thanks again. To be more precise with my code, here it is

Customer-record-reader.xml

<batch:job id="myFileReaderJob">
    <batch:step id="stepA" next="stepSuccess">
        <batch:tasklet>        
        <batch:chunk reader="myInputReader" processor="myProcessor" writer="myWriter" commit-interval="1"/>
        </batch:tasklet>
    </batch:step>
    <batch:step id="stepSuccess">
        <batch:tasklet ref="successTasklet" />
    </batch:step>
</batch:job>

<bean id="myInputReader" scope="step" class="org.springframework.batch.item.file.FlatFileItemReader">
        <property name="lineMapper" ref="myLineMapper" />
</bean>

<bean id="myLineMapper" class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean id="fixedLengthLineTokenizer" class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
        <property name="names" value="custRecord,tranId,partyId,uniquePartyId,deNum,deVal" />
        <property name="columns" value="1-75,1-3,6-11,21-29,30-32,33-62" />
        <property name="strict" value="false" />
    </bean>
</property>
<property name="fieldSetMapper">
    <bean       class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
        <property name="prototypeBeanName" value="myInputData" />
    </bean>
</property>
</bean>

As you can see, I am not using a custom implementation of ItemReader to wrap the FlatFileItemReader. Can you elaborate more in detail, on how to make changes in this code above to implement the SingleItemPeekableItemReader.

Thanks

@Dean
I tried implementing as per your suggestion

Config1.xml
<import resource="classpath*:/META-INF/java-batchlauncher/mainConfig.xml" />

<batch:job id="prT813FileReaderJob">
        <batch:step id="stepA" next="stepB">
            <batch:tasklet ref="aTasklet" />
        </batch:step>
        <batch:step id="stepB" next="stepSuccess">
            <batch:tasklet>        
                <batch:chunk reader="prT813MultiReader" processor="participantRecordT813Processor" writer="prT813ItemWriter" commit-interval="1"/>
                <batch:listeners>
                    <batch:listener ref="enabledFeaturesStepListener"/>
                </batch:listeners>
                <batch:transaction-attributes propagation="NEVER"/> 
            </batch:tasklet>
        </batch:step>
        <batch:step id="stepSuccess">
            <batch:tasklet ref="successTasklet" />
        </batch:step>
    </batch:job>

My mainConfig.xml file changes:

<bean id="prT813MultiReader" scope="step" class="org.springframework.batch.item.file.MultiResourceItemReader">
        <property name="resources" value="#{jobParameters[INPUT_FILES]}" />
        <property name="delegate" ref="prT813InputReader" />
</bean>

<bean id="prT813MultiThreadedReader" scope="step" class="org.springframework.batch.item.file.MultiResourceItemReader">
        <property name="resources" value="#{stepExecutionContext[fileName]}" />
        <property name="delegate" ref="prT813InputReader" />
    </bean>

<bean id="prT813InputReader" scope="step" class="com.fileprocessing.ParticipantRecordT813ItemReader">
        <property name="delegate" ref="prT813CustomPeekableItemReader" />
    </bean>

    <bean id="prT813CustomPeekableItemReader" scope="step" class="org.springframework.batch.item.support.SingleItemPeekableItemReader">
        <property name="delegate" ref="participantRecordT813ItemReader" />
    </bean>

    <bean id="participantRecordT813ItemReader" scope="step" class="org.springframework.batch.item.file.FlatFileItemReader">
        <property name="lineMapper" ref="prT813LineMapper" />
    </bean>


Created a new Reader class:
public class ParticipantRecordT813ItemReader extends SingleItemPeekableItemReader<ParticipantRecordT813InputData> {

    private static final String CLASS = "ParticipantRecordT813ItemReader"; 

    @Override
    public ParticipantRecordT813InputData read() throws UnexpectedInputException, ParseException, Exception {

        ParticipantRecordT813InputData item = super.read();
        Log.report(CLASS, "I am in the reader ::::");
        if (item != null) {
            while (item.getDeNum()=="551") {
                Log.report(CLASS, "I am in the reader at DE551::::" + item.getDeNum());
                ParticipantRecordT813InputData possibleRelatedObject = peek();
                if (possibleRelatedObject == null) {
                    return item;
                }

                //logic to determine if next line in file relates to same object
                boolean matches = possibleRelatedObject.getDeNum()=="552"; 

                if (matches) {
                    Log.report(CLASS, "I am in the reader at DE552::::" + possibleRelatedObject.getDeNum());
                } else {
                    return item;
                }
            }
        }
        return item;
    }
}

I am getting the below exception:

ERROR [main] (AbstractStep.java:225)- Encountered an error executing step stepB in job prT813FileReaderJob
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.prT813MultiReader' defined in URL []: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.sun.proxy.$Proxy10 implementing org.springframework.batch.item.ItemStreamReader,org.springframework.batch.item.PeekableItemReader,java.io.Serializable,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.springframework.batch.item.file.ResourceAwareItemReaderItemStream' for property 'delegate'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy10 implementing org.springframework.batch.item.ItemStreamReader,org.springframework.batch.item.PeekableItemReader,java.io.Serializable,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.item.file.ResourceAwareItemReaderItemStream] for property 'delegate': no matching editors or conversion strategy found







As you can see that prT813MultiReader and prT813MultiThreadedReader of type MultiResourceItemReader and I delegate them to prT813InputReader of type SingleItemPeekableItemReader.







I tried implementing ResourceAwareItemReaderItemStream in my reader class which get rid of the above exception but then it complaints on ParticipantRecordT813InputData item = super.read(); for nullPointerException. 

public class ParticipantRecordT813ItemReader extends SingleItemPeekableItemReader<ParticipantRecordT813InputData> implements ResourceAwareItemReaderItemStream<ParticipantRecordT813InputData> {

    private static final String CLASS = "ParticipantRecordT813ItemReader";
    SingleItemPeekableItemReader<ParticipantRecordT813InputData> delegate = new SingleItemPeekableItemReader<ParticipantRecordT813InputData>(); 

    @Override
    public ParticipantRecordT813InputData read() throws UnexpectedInputException, ParseException, Exception {

        ParticipantRecordT813InputData item = super.read();
        Log.report(CLASS, "I am in the reader ::::");
        if (item != null) {
            while (item.getDeNum()=="551") {
                Log.report(CLASS, "I am in the reader at DE551::::" + item.getDeNum());
                ParticipantRecordT813InputData possibleRelatedObject = peek();
                if (possibleRelatedObject == null) {
                    return item;
                }

                //logic to determine if next line in file relates to same object
                boolean matches = possibleRelatedObject.getDeNum()=="552"; 

                if (matches) {
                    Log.report(CLASS, "I am in the reader at DE552::::" + possibleRelatedObject.getDeNum());
                } else {
                    return item;
                }
            }
        }
        return item;
    }

    @Override
    public void close() throws ItemStreamException {
        // TODO Auto-generated method stub
        super.close();
    }

    @Override
    public void open(ExecutionContext arg0) throws ItemStreamException {
        // TODO Auto-generated method stub
        super.open(arg0);
    }

    @Override
    public void update(ExecutionContext arg0) throws ItemStreamException {
        // TODO Auto-generated method stub
        super.update(arg0);
    }

    @Override
    public void setResource(Resource arg0) {
        // TODO Auto-generated method stub
        super.setDelegate(delegate);        
    }
}


Any idea where I am wrong????
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!