Accessing the ExecutionContext values in HeaderCallBack in Spring Batch

丶灬走出姿态 提交于 2020-01-30 12:03:06

问题


I'm trying to write a spring batch job which reads data from database and writes to FlatFile. I need to write the total records, total lines in the header of the FlatFile. Using the headerCallback property in Writer for that purpose.

Problem statement:

I'm setting the values in ExecutionContext in Processor and trying to retrieve the values in headerCallback of the Writer. But getting the values as null in headerCallback.

Tried using ExecutionContextPromotionListener and also by injecting the values directly into headerCallback using SpEL. Details are as below:

Job configuration:

<batch:job id="fooBatchJob">
<batch:step id="step1">
        <batch:tasklet>
            <batch:chunk reader="fooJdbcItemReader" writer="fooFileItemWriter" processor="fooProcessor"
                commit-interval="100">
            </batch:chunk>
        </batch:tasklet>
        <batch:listeners>
            <batch:listener ref="execContextPromotionListener"/>
        </batch:listeners>
    </batch:step>
</batch:job>

<!-- Listeners -->

<bean id="execContextPromotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">
    <property name="strict" value="TRUE"/>
    <property name="keys">
        <list>
            <value>TOTAL_RECORDS</value>
            <value>TOTAL_LINES</value>
        </list>
    </property>
</bean>

The values of TOTAL_RECORDS and TOTAL_LINES are populated with the values from the query in ItemReader.

I'm setting the values in Processor as below:

public class FooProcessor implements ItemProcessor<MyObj,MyObj>, StepExecutionListener {

    private StepExecution stepExecution;

    public MyObj process(MyObj item) throws Exception {

        if(item != null && item.getRecordType().equals("HEADER")) {

            this.stepExecution.getExecutionContext().put("TOTAL_RECORDS", item.getMetaData().getTotalRecordsCount());
            this.stepExecution.getExecutionContext().put("TOTAL_LINES", item.getMetaData().getTotalLines());
            // below lines printed for debugging:
            System.out.println("TOTAL_RECORDS:"+this.stepExecution.getExecutionContext().getInt("TOTAL_RECORDS"));
            System.out.println("TOTAL_LINES:"+this.stepExecution.getExecutionContext().getInt("TOTAL_LINES"));
            return null;
        }
        return item;
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {
        this.stepExecution = stepExecution;

    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return null;
    }
}

Now, here is the Writer configuration:

<bean id="fooFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
        <property name="resource" value="file:output/result-file.asc"/>
        <property name="shouldDeleteIfExists" value="true" />
        <property name="headerCallback" ref="myHeaderFooter"/>
        <property name="footerCallback" ref="myHeaderFooter"/>
        <property name="lineAggregator">
            <bean
                class="com.domain.batch.transform.FooLineAggregator">
            </bean>
        </property>
    </bean> 

<!-- Header and Footer Callback -->
    <bean id="myHeaderFooter" class="com.domain.batch.transform.MyHeaderFooter" scope="step">
        <property name="stepExecution" value="#{stepExecution}" />
        <property name="totalRecords" value="#{jobExecutionContext['TOTAL_RECORDS']}"/>
    </bean> 

Below is the listing of MyHeaderFooter.java:

public class MyHeaderFooter implements FlatFileHeaderCallback, FlatFileFooterCallback {

    private StepExecution stepExecution;
    private Integer totalRecords;

    private static final String ITEM_END_INDICATOR = "RE";
    private static final String SPACE_DELIMITER = " ";
    private static final String LINE_SEPARATOR = System.lineSeparator();

    @Override
    public void writeHeader(Writer writer) throws IOException {
        // printing out null
        System.out.println("Total records from jobExecContext : "+totalRecords); 
        ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
        // printing out null
        System.out.println("Total Records :"+ executionContext.get("TOTAL_RECORDS"));
       // printing out null
        System.out.println("Total Lines:"+ executionContext.get("TOTAL_LINES"));
        // Below lines commented out for brevity
        //String header = buildHeader(...);
        //writer.write(header);
    }

    @Override
    public void writeFooter(Writer writer) throws IOException {
        String footer = "footer data....";
        writer.write(footer);
    }

public void setStepExecution(StepExecution stepExecution) {
        this.stepExecution = stepExecution;
    }

    public void setTotalRecords(Integer totalRecords) {
        this.totalRecords = totalRecords;
    }
}

Not sure what i'm doing wrong with the configuration. Any clue to find out the issue would be helpful.


回答1:


The writeHeader method is called while opening the fooFileItemWriter. Reading, processing and writing have not started yet at that point in time. So the information you are requesting is not available yet.

Note that it would work if you want to write these information in a footer line.

There is a similar question to this one, I'm adding it here for reference: Passing variables to process.



来源:https://stackoverflow.com/questions/52076902/accessing-the-executioncontext-values-in-headercallback-in-spring-batch

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