1. Intro to Spring Batch
1) Spring Batch is a framework for Batch Processing - Execution of a series of Jobs.
2) Each "Job" contains many "Steps". And one "Step" can be a single "tasklet" or a "READ-PROCESS-WRITE" task.
2. An overview of Spring Batch
3. Example for Tasklet
A sample tasklet delete all files under a specific folder.
context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <import resource="../jobs/tasklet.xml" /> <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> <property name="jobRepository" ref="jobRepository" /> </bean> <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"> <property name="transactionManager" ref="transactionManager" /> </bean> <bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /> </beans>
tasklet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <batch:job id="taskletExampleJob"> <batch:step id="cleanFolder"> <batch:tasklet ref="cleanResourceFolderTasklet" /> </batch:step> </batch:job> <bean id="cleanResourceFolderTasklet" class="edu.xmu.spring.batch.tasklet.CleanResourceFolderTasklet"> <property name="directory" value="file:csv/bak" /> </bean> </beans>
App.java
package edu.xmu.spring.batch; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( new String[] { "spring/batch/config/context.xml" }); JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher"); Job job = (Job) context.getBean("taskletExampleJob"); JobExecution execution; try { execution = jobLauncher.run(job, new JobParameters()); System.out.println("Exit Status : " + execution.getStatus()); } catch (Exception e) { e.printStackTrace(); } System.out.println("Done"); context.close(); } }
CleanResourceFolderTasklet.java
package edu.xmu.spring.batch.tasklet; import java.io.File; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.UnexpectedJobExecutionException; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import org.springframework.util.Assert; public class CleanResourceFolderTasklet implements Tasklet, InitializingBean { private Resource directory; @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { File dir = directory.getFile(); Assert.state(dir.isDirectory()); File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { boolean deleted = files[i].delete(); if (!deleted) { throw new UnexpectedJobExecutionException( "Could not delete file " + files[i].getPath()); } else { System.out.println(files[i].getPath() + " is deleted!"); } } return RepeatStatus.FINISHED; } @Override public void afterPropertiesSet() throws Exception { Assert.notNull(directory, "directory must be set"); } public Resource getDirectory() { return directory; } public void setDirectory(Resource directory) { this.directory = directory; } }
4. Example for Job(Read-Process-Write)
Read from csv and write to csv.
context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <import resource="../jobs/job.xml" /> <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> <property name="jobRepository" ref="jobRepository" /> </bean> <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"> <property name="transactionManager" ref="transactionManager" /> </bean> <bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /> </beans>
job.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <batch:job id="readProcessWriteExampleJob"> <batch:step id="readAndWriteStep"> <batch:tasklet> <batch:chunk reader="cvsFileItemReader" processor="csvItemProcessor" writer="csvItemWriter" commit-interval="10" /> </batch:tasklet> </batch:step> </batch:job> <bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader"> <property name="resource" value="file:csv/input/user.csv" /> <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, password" /> </bean> </property> <property name="fieldSetMapper"> <bean class="edu.xmu.spring.batch.UserFieldSetMapper" /> </property> </bean> </property> </bean> <bean id="csvItemProcessor" class="edu.xmu.spring.batch.processor.UserCsvItemProcessor" /> <bean id="csvItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter"> <property name="resource" value="file:csv/output/user.csv" /> <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, username, password" /> </bean> </property> </bean> </property> </bean> </beans>
User.java
package edu.xmu.spring.batch.model; public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
UserFieldSetMapper.java
package edu.xmu.spring.batch; import org.springframework.batch.item.file.mapping.FieldSetMapper; import org.springframework.batch.item.file.transform.FieldSet; import org.springframework.validation.BindException; import edu.xmu.spring.batch.model.User; public class UserFieldSetMapper implements FieldSetMapper<User> { @Override public User mapFieldSet(FieldSet fieldSet) throws BindException { User user = new User(); user.setId(fieldSet.readInt("id")); user.setUsername(fieldSet.readString("name")); user.setPassword(fieldSet.readString("password")); return user; } }
UserCsvItemProcessor.java
package edu.xmu.spring.batch.processor; import org.springframework.batch.item.ItemProcessor; import edu.xmu.spring.batch.model.User; public class UserCsvItemProcessor implements ItemProcessor<User, User> { @Override public User process(User item) throws Exception { item.setUsername(item.getUsername().replace(',', '-')); item.setPassword(item.getPassword().replace(',', '-')); return item; } }
App.java
package edu.xmu.spring.batch; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( new String[] { "spring/batch/config/context.xml" }); JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher"); Job job = (Job) context.getBean("readProcessWriteExampleJob"); JobExecution execution; try { execution = jobLauncher.run(job, new JobParameters()); System.out.println("Exit Status : " + execution.getStatus()); } catch (Exception e) { e.printStackTrace(); } System.out.println("Done"); context.close(); } }
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>edu.xmu.spring.batch</groupId> <artifactId>spring-batch</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <spring.version>3.2.2.RELEASE</spring.version> <spring.batch.version>2.2.0.RELEASE</spring.batch.version> <junit.version>4.11</junit.version> </properties> <dependencies> <!-- Spring Core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring Batch dependencies --> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-core</artifactId> <version>${spring.batch.version}</version> </dependency> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-infrastructure</artifactId> <version>${spring.batch.version}</version> </dependency> </dependencies> </project>
Reference Links:
1) http://www.mkyong.com/spring-batch/