Adding Step Level Listeners using StepExecutionListener

In this post of Spring Batch, I will explain how to add step level listeners.

Spring Batch provides a facility to add listeners at step level. The listeners are executed before the step is started and after the step is finished.

This post explains how to create step level listeners and integrate them with the job. We can add our custom processing logic in these listeners and expect them to be called before and
after the step execution.

To create listeners, we need to create class that implements org.springframework.batch.core.StepExecutionListener interface as shown below

Listener Code


1  package package9;
2  
3  import org.springframework.batch.core.ExitStatus;
4  import org.springframework.batch.core.StepExecution;
5  import org.springframework.batch.core.StepExecutionListener;
6  
7  public class CustomStepListener implements StepExecutionListener {
8  
9   @Override
10  public ExitStatus afterStep(StepExecution stepExecution) {
11      System.out.println(stepExecution.getStepName() + " step ended");
12      return stepExecution.getExitStatus();
13  }
14 
15  @Override
16  public void beforeStep(StepExecution stepExecution) {
17      System.out.println(stepExecution.getStepName() + " step started");
18  }
19 }

We need to provide implementation for two interface methods “afterStep” and “beforeStep”.

In case of “afterStep” method we need to return the status of the current step to the next step. So at line 12 we are returning the status.

An instance of StepExecution provide access to current step’s execution data.

Next we need to integrate with job using xml configuration as shown below


1   <bean id="customStepListener" class="package9.CustomStepListener"/>
2   
3   <batch:job id="importProductsJob">
4       <batch:step id="readWriteProducts">
5           <batch:tasklet>
6               <batch:chunk reader="reader" writer="writer" commit-interval="50"/>
7               <batch:listeners>
8                   <batch:listener ref="customStepListener"/>
9               </batch:listeners>
10          </batch:tasklet>
11      </batch:step>
12  </batch:job>

At line 1 we create a bean definition of type CustomStepListener.

At line 8 we integrate it with job by using batch:listener tag.

Below is the complete xml configuration


<?xml version="1.0" encoding="UTF-8"?>
<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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">
    
    <bean id="employee" class="package9.Employee" scope="prototype"/>
    
    <bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
        <property name="resource" value="file:DemoData1.txt"/>
        <property name="linesToSkip" value="1"/>
        <property name="lineMapper">
            <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                <property name="lineTokenizer">
                    <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                        <property name="names" value="id,name,status,salary"/>
                    </bean>
                </property>
                <property name="fieldSetMapper">
                    <bean class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
                        <property name="prototypeBeanName" value="employee"/>
                    </bean>
                </property>
            </bean>
        </property> 
    </bean>
    
    <bean id="writer" class="org.springframework.batch.item.file.FlatFileItemWriter">
        <property name="resource" value="file:DemoData2.txt"/>
        <property name="lineAggregator">
            <bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
                <property name="fieldExtractor">
                    <bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
                        <property name="names" value="id,name,status,salary"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    
    <bean id="customStepListener" class="package9.CustomStepListener"/>
    
    <batch:job id="importProductsJob">
        <batch:step id="readWriteProducts">
            <batch:tasklet>
                <batch:chunk reader="reader" writer="writer" commit-interval="50"/>
                <batch:listeners>
                    <batch:listener ref="customStepListener"/>
                </batch:listeners>
            </batch:tasklet>
        </batch:step>
    </batch:job>
    
    <bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
    
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
    
    <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository"/>
    </bean>
</beans>

Output

Sep 09, 2018 11:14:36 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@61e4705b: startup date [Sun Sep 09 11:14:36 IST 2018]; root of context hierarchy
Sep 09, 2018 11:14:37 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [package9/job.xml]
Sep 09, 2018 11:14:38 AM org.springframework.batch.core.launch.support.SimpleJobLauncher afterPropertiesSet
INFO: No TaskExecutor has been set, defaulting to synchronous executor.
Sep 09, 2018 11:14:38 AM org.springframework.batch.core.launch.support.SimpleJobLauncher run
INFO: Job: [FlowJob: [name=importProductsJob]] launched with the following parameters: [{date=1536471878359}]
Sep 09, 2018 11:14:38 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [readWriteProducts]
readWriteProducts step started
readWriteProducts step ended
Sep 09, 2018 11:14:38 AM org.springframework.batch.core.launch.support.SimpleJobLauncher run
INFO: Job: [FlowJob: [name=importProductsJob]] completed with the following parameters: [{date=1536471878359}] and the following status: [COMPLETED]

Leave a Reply