Adding job level listeners using JobExecutionListener

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

This post explains how to create 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 job execution.

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

Listener class


1  package package4;
2  
3  import org.springframework.batch.core.JobExecution;
4  import org.springframework.batch.core.JobExecutionListener;
5  
6  public class ImportEmployeeJobListener implements JobExecutionListener {
7   @Override
8   public void afterJob(JobExecution jobExecution) {
9       System.out.println("Job Finished: " + jobExecution.getStatus());
10  }
11 
12  @Override
13  public void beforeJob(JobExecution jobExecution) {
14      System.out.println("Job Started");
15  }
16 }

In the above code we created a class named ImportEmployeeJobListener that implements JobExecutionListener.

The class provides implementation for the two interface methods named “afterJob” and “beforeJob”. “afterJob” method is called after the job is finished and “beforeJob” method is
called before the job is started. Both these methods receive an instance of JobExecution as a parameter.

An instance of JobExecution instance provides information regarding job execution status.

No we need to integrate it with the job by the help of below xml configuration

XML configuration


1   <bean id="importEmployeeJobListener" class="package4.ImportEmployeeJobListener" />
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:tasklet>
8       </batch:step>
9       <batch:listeners>
10          <batch:listener ref="importEmployeeJobListener"/>
11      </batch:listeners>
12  </batch:job>

At line 1, we define a bean of class ImportEmployeeJobListener. We refer to this bean at line 10 and set it to listener property of job.

When we execute the job the below output is displayed

Output

Aug 19, 2018 9:24:25 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@32a1bec0: startup date [Sun Aug 19 09:24:25 IST 2018]; root of context hierarchy
Aug 19, 2018 9:24:26 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [package4/job.xml]
Aug 19, 2018 9:24:27 AM org.springframework.batch.core.launch.support.SimpleJobLauncher afterPropertiesSet
INFO: No TaskExecutor has been set, defaulting to synchronous executor.
Aug 19, 2018 9:24:27 AM org.springframework.batch.core.launch.support.SimpleJobLauncher run
INFO: Job: [FlowJob: [name=importProductsJob]] launched with the following parameters: [{date=1534650867430}]
Job Started
Aug 19, 2018 9:24:27 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [readWriteProducts]
Job Finished: COMPLETED
Aug 19, 2018 9:24:27 AM org.springframework.batch.core.launch.support.SimpleJobLauncher run
INFO: Job: [FlowJob: [name=importProductsJob]] completed with the following parameters: [{date=1534650867430}] and the following status: [COMPLETED]

Below is the complete job xml configuration

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="package4.Employee" scope="prototype"/>
    
    <bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
        <property name="resource" value="file:FileInput.txt"/>
        <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="importEmployeeJobListener" class="package4.ImportEmployeeJobListener" />
    
    <batch:job id="importProductsJob">
        <batch:step id="readWriteProducts">
            <batch:tasklet>
                <batch:chunk reader="reader" writer="writer" commit-interval="50"/>
            </batch:tasklet>
        </batch:step>
        <batch:listeners>
            <batch:listener ref="importEmployeeJobListener"/>
        </batch:listeners>
    </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>

Leave a Reply