Chaining multiple ItemProcessorListener

In this post under Spring Batch, I will explain with example how to chain multiple ItemProcessorListeners.

For our example we create two ItemProcessorListener as shown below

CustomItemProcessListener1


package package34;

import org.springframework.batch.core.ItemProcessListener;

public class CustomItemProcessListener1 implements ItemProcessListener {
	@Override
	public void afterProcess(Employee employee1, Employee employee2) {
		System.out.println("CustomItemProcessListener1: Item processing completed");
	}

	@Override
	public void beforeProcess(Employee employee) {
		System.out.println("CustomItemProcessListener1: Item processing started");
	}

	@Override
	public void onProcessError(Employee employee, Exception exception) {
		exception.printStackTrace();
	}
}

CustomItemProcessListener2


package package34;

import org.springframework.batch.core.ItemProcessListener;

public class CustomItemProcessListener2 implements ItemProcessListener {
	@Override
	public void afterProcess(Employee employee1, Employee employee2) {
		System.out.println("CustomItemProcessListener2: Item processing completed");
	}

	@Override
	public void beforeProcess(Employee employee) {
		System.out.println("CustomItemProcessListener2: Item processing started");
	}

	@Override
	public void onProcessError(Employee employee, Exception exception) {
		exception.printStackTrace();
	}
}

Now we will create an ItemProcessor as shown below

EmployeeFilterItemProcessor


package package34;

import org.springframework.batch.item.ItemProcessor;

public class EmployeeFilterItemProcessor implements ItemProcessor {
	int i = 0;
	
	@Override
	public Employee process(Employee employee) throws Exception {
		Employee employee1;
		
		if(i%2 == 0) {
			employee1 = employee;
		} else {
			employee1 = null;
		}
		i = i + 1;
		return employee1;
	}
}

As per the above code, employee records at odd position in the source file are filtered out, whereas employee records at even position will be written to destination
file.

Now we will integrate all three classes with job as shown in below xml


1 	<bean id="customItemProcessListener1" class="package34.CustomItemProcessListener1"/>
2 	
3 	<bean id="customItemProcessListener2" class="package34.CustomItemProcessListener2"/>
4 	
5 	<bean id="employeeFilterItemProcessor" class="package34.EmployeeFilterItemProcessor" />
6 	
7 	<bean id="compositeItemProcessListener" class="org.springframework.batch.core.listener.CompositeItemProcessListener">
8 		<property name="listeners">
9 			<list>
10				<ref bean="customItemProcessListener1"/>
11				<ref bean="customItemProcessListener2"/>
12			</list>
13		</property>
14	</bean>
15	
16	<batch:job id="importEmployees">
17		<batch:step id="readWriteEmployees">
18			<batch:tasklet>
19				<batch:chunk reader="reader" writer="writer" processor="employeeFilterItemProcessor" commit-interval="50"/>
20			</batch:tasklet>
21			<batch:listeners>
22				<batch:listener ref="compositeItemProcessListener"/>
23			</batch:listeners>
24		</batch:step>
25	</batch:job>

In the above xml code, at line 1 I create a bean definition for CustomItemProcessListener1.

At line 3 I create a bean definition for CustomItemProcessListener2.

At line 5 I create a bean definition for EmployeeFilterItemProcessor.

From line 7 to 14 I have created a bean definition for CompositeItemProcessListener class. It takes a list of ItemProcessListener’s, so we have provided a list and
in the list we are referring to the bean created at line 1 and 3.

Next from line 21 to 23 we integrate the compositeItemProcessListener bean to the job.

In this way we chain multiple ItemProcessListeners and integrate with the Spring Batch job.

Below is the xml code for your reference.


<?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="package34.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:FileOutput.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="customItemProcessListener1" class="package34.CustomItemProcessListener1"/>
	
	<bean id="customItemProcessListener2" class="package34.CustomItemProcessListener2"/>
	
	<bean id="employeeFilterItemProcessor" class="package34.EmployeeFilterItemProcessor" />
	
	<bean id="compositeItemProcessListener" class="org.springframework.batch.core.listener.CompositeItemProcessListener">
		<property name="listeners">
			<list>
				<ref bean="customItemProcessListener1"/>
				<ref bean="customItemProcessListener2"/>
			</list>
		</property>
	</bean>
	
	<batch:job id="importEmployees">
		<batch:step id="readWriteEmployees">
			<batch:tasklet>
				<batch:chunk reader="reader" writer="writer" processor="employeeFilterItemProcessor" commit-interval="50"/>
			</batch:tasklet>
			<batch:listeners>
				<batch:listener ref="compositeItemProcessListener"/>
			</batch:listeners>
		</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>

Leave a Reply