Spring Boot + Spring Batch Scheduler(2021) Hello World Example | CodeUsingJava






















Spring Boot + Spring Batch Scheduler(2021) Hello World Example

In this tutorial we will be implementing Spring Boot Batch Scheduler with the help of example.
Spring Batch is one of the open-source framework available for batch processing. Sometimes, while working on enterprise applications, we need to perform spring batch jobs from time to time or periodically on fixed time. This can be done by using some cron expression which is passed to Spring TaskScheduler.
In this example, with the help of spring scheduling capability, we will configure a simple Job with a Tasklet that brings the data from the database and prints it in the csv file. This tasklet will be executed after certain amount of time with the help of specifying fixed rate , fixed delay or using cron expression. It is assumed that the reader is known with the basic terms like job, step etc. that are present in spring batch scheduling.

Table Of Contents :


  • This will be the standard directory layout for maven project structure-
    Spring Boot Maven Project
    We need to start by creating a Maven pom.xml(Project Object Model) file. The pom.xml file contains the project configuration details.
    	<?xml version="1.0" encoding="UTF-8"?>
    	<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>com.codeusingjava.batch</groupId>
    		<artifactId>SpringBootBatchScheduler</artifactId>
    		<version>0.0.1-SNAPSHOT</version>
    		<packaging>jar</packaging>
    	
    		<name>SpringBootBatchScheduler</name>
    		<description>Demo project for Spring Boot</description>
    	
    		<parent>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-parent</artifactId>
    			<version>1.5.6.RELEASE</version>
    			<relativePath />
    		</parent>
    	
    		<properties>
    			<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    			<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    			<java.version>1.8</java.version>
    		</properties>
    	
    		<dependencies>
    			<dependency>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-starter-batch</artifactId>
    			</dependency>
    			<dependency>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-starter-jdbc</artifactId>
    			</dependency>
    	
    			<dependency>
    				<groupId>mysql</groupId>
    				<artifactId>mysql-connector-java</artifactId>
    				<scope>runtime</scope>
    			</dependency>
    			<dependency>
    
    			<!-- It helps in serialise and deserialize objects -->
    				<groupId>com.thoughtworks.xstream</groupId>
    				<artifactId>xstream</artifactId>
    				<version>1.4.9</version>
    			</dependency>
    			<dependency>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-starter-test</artifactId>
    				<scope>test</scope>
    			</dependency>
    		</dependencies>
    	
    		<build>
    			<plugins>
    				<plugin>
    					<groupId>org.springframework.boot</groupId>
    					<artifactId>spring-boot-maven-plugin</artifactId>
    				</plugin>
    			</plugins>
    		</build>
    	
    	</project>
    	
    
    Creating the Database configuration in application.properties as follows-
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
    spring.datasource.password=****
    spring.datasource.username=root
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.initialize=false
    spring.datasource.schema=classpath:schema.sql
    
    
    Inside schema.sql, the query to create a table in database is present.Paste this content in the mysql workbench.
    Now insert some dummy data into the table.
    	CREATE TABLE IF NOT EXISTS person  (
        person_id BIGINT auto_increment NOT NULL PRIMARY KEY,
        first_name VARCHAR(40),
        last_name VARCHAR(40),
        email VARCHAR(100),
        age INT
    );
    
    Creating the User model class as follows-
    	package com.codeusingjava.model;
    
    	public class User {
    	
    		private Integer personId;
    		private String firstName;
    		private String lastName;
    		private String email;
    		private Integer age;
    		public Integer getPersonId() {
    			return userId;
    		}
    		public void setPersonId(Integer personId) {
    			this.personId = personId;
    		}
    		public String getFirstName() {
    			return firstName;
    		}
    		public void setFirstName(String firstName) {
    			this.firstName = firstName;
    		}
    		public String getLastName() {
    			return lastName;
    		}
    		public void setLastName(String lastName) {
    			this.lastName = lastName;
    		}
    		public String getEmail() {
    			return email;
    		}
    		public void setEmail(String email) {
    			this.email = email;
    		}
    		public Integer getAge() {
    			return age;
    		}
    		public void setAge(Integer age) {
    			this.age = age;
    		}
    	}
    	
    
    Creating the class for Spring Batch configuration
    Here, RowMapper interface is used to map one by one rows of the ResultSet.
    The method writer from the FlatFileItemWriter takes a single object and then write that object in a flat file.
    package com.codeusingjava.config;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import org.springframework.batch.core.Job;
    import org.springframework.batch.core.Step;
    import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
    import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
    import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
    import org.springframework.batch.core.launch.support.RunIdIncrementer;
    import org.springframework.batch.item.database.JdbcCursorItemReader;
    import org.springframework.batch.item.file.FlatFileItemWriter;
    import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
    import org.springframework.batch.item.file.transform.DelimitedLineAggregator;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.jdbc.core.RowMapper;
    
    import com.codeusingjava.model.User;
    import com.codeusingjava.processor.UserItemProcessor;
    
    @Configuration
    @EnableBatchProcessing
    public class BatchConfig {
    	
    	@Autowired
    	private JobBuilderFactory jobBuilderFactory;
    	
    	@Autowired
    	private StepBuilderFactory stepBuilderFactory;
    	
    	@Autowired
    	private DataSource dataSource;
    	
    	@Bean
    	public JdbcCursorItemReader<User> reader(){
    		JdbcCursorItemReader<User> cursorItemReader = new JdbcCursorItemReader<>();
    		cursorItemReader.setDataSource(dataSource);
    		cursorItemReader.setSql("SELECT person_id,first_name,last_name,email,age FROM person");
    		cursorItemReader.setRowMapper(new UserRowMapper());
    		return cursorItemReader;
    	}
    	
    	@Bean
    	public UserItemProcessor processor(){
    		return new UserItemProcessor();
    	}
    	
    	@Bean
    	public FlatFileItemWriter<User> writer(){
    		FlatFileItemWriter<User> writer = new FlatFileItemWriter<User>();
    		writer.setResource(new ClassPathResource("persons.csv"));
    		
    		DelimitedLineAggregator<User> lineAggregator = new DelimitedLineAggregator<User>();
    		lineAggregator.setDelimiter(",");
    		
    		BeanWrapperFieldExtractor<User>  fieldExtractor = new BeanWrapperFieldExtractor<User>();
    		fieldExtractor.setNames(new String[]{"personId","firstName","lastName","email","age"});
    		lineAggregator.setFieldExtractor(fieldExtractor);
    		
    		writer.setLineAggregator(lineAggregator);
    		return writer;
    	}
    	
    	@Bean
    	public Step step1(){
    		return stepBuilderFactory.get("step1").<User,User>chunk(10).reader(reader()).processor(processor()).writer(writer()).build();
    	}
    
    	@Bean
    	public Job exportPerosnJob(){
    		return jobBuilderFactory.get("exportPersonJob").incrementer(new RunIdIncrementer()).flow(step1()).end().build();
    	}
    }
    
    class UserRowMapper implements RowMapper<User> {
    
    	@Override
    	public User mapRow(ResultSet rs, int rowNum) throws SQLException {
    		User person = new User();
    		person.setPersonId(rs.getInt("person_id"));
    		person.setFirstName(rs.getString("first_name"));
    		person.setLastName(rs.getString("last_name"));
    		person.setEmail(rs.getString("email"));
    		person.setAge(rs.getInt("age"));
    		return person;
    	}
    
    }
    
    Creating the class for Spring Scheduler configuration
    The @EnableScheduling annotation can enable the Scheduler in our application.
    @Scheduled annotation is used to task scheduling.
    We can schedule a task by using fixed rate,fixed delay attribute or using cron.
    The cron expression signifies that the task will be scheduled after every 10 milliseconds.
    	package com.codeusingjava.config;
    
    	import org.springframework.batch.core.Job;
    	import org.springframework.batch.core.JobExecution;
    	import org.springframework.batch.core.JobParameters;
    	import org.springframework.batch.core.JobParametersBuilder;
    	import org.springframework.batch.core.JobParametersInvalidException;
    	import org.springframework.batch.core.launch.JobLauncher;
    	import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
    	import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
    	import org.springframework.batch.core.repository.JobRestartException;
    	import org.springframework.beans.factory.annotation.Autowired;
    	import org.springframework.scheduling.annotation.EnableScheduling;
    	import org.springframework.scheduling.annotation.Scheduled;
    	import org.springframework.stereotype.Component;
    	
    	@Component
    	@EnableScheduling
    	public class MyScheduler {
    	
    		@Autowired
    		private JobLauncher jobLauncher;
    		
    		@Autowired
    		private Job job;
    		
    		@Scheduled(cron="*/10 * * * * *")
    		public void myScheduler(){
    			JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()).toJobParameters();
    			
    			try {
    				JobExecution jobExecution = jobLauncher.run(job, jobParameters);
    				System.out.println("Job's Status:::"+jobExecution.getStatus());
    			} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
    					| JobParametersInvalidException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	
    
    Creating the processor class
    The processor class reads each and every data element, then processes the data and finally writes the processed record in the writer.
    	package com.codeusingjava.processor;
    
    	import org.springframework.batch.item.ItemProcessor;
    	
    	import com.codeusingjava.model.User;
    	
    	public class UserItemProcessor implements ItemProcessor<User, User>{
    	
    		@Override
    		public User process(User person) throws Exception {
    			return person;
    		}
    	}
    	
    
    Run the following Spring Boot class for starting our application.
    package com.codeusingjava;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SpringBootBatchSchedulerApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(SpringBootBatchSchedulerApplication.class, args);
    	}
    }
    
    
If we now run the application we get the output as follows:-
Spring Boot Batch Scheduler Output
To see the database records into a csv file , go to the following locations inside the project:-
target-< open in -< System Explorer -<classes -<persons.csv
Spring Boot Batch CSV

Downloads-

Spring Boot + Spring Batch Scheduler Example