Thursday, July 16, 2020

# Spring Batch Job #


Spring Boot Batch Job + Scheduler Simple Example
In a previous post we had implemented a Spring Boot Hello World Application. In that the Batch Job got triggered by a REST API call. In this post we develop a simple Spring Boot Batch application where batch job gets triggered using a scheduler.
Consider the simple use case where the user wants to delete files from a particular location everyday at a particular time. We will schedule this batch job using the scheduler.
Description: boot-23_1





Lets Begin-
The project will be as follows-
Description: boot-23_2
<?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.javainuse</groupId>
         <artifactId>springboot-batch</artifactId>
         <version>0.0.1</version>
         <packaging>jar</packaging>

         <name>SpringBatch</name>
         <description>Spring Batch-Spring Boot</description>

         <parent>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-parent</artifactId>
                 <version>1.4.3.RELEASE</version>
                 <relativePath /> <!-- lookup parent from repository -->
         </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</artifactId>
                 </dependency>

                 <dependency>
                          <groupId>org.springframework.boot</groupId>
                          <artifactId>spring-boot-starter-batch</artifactId>
                 </dependency>
         </dependencies>

         <build>
                 <plugins>
                          <plugin>
                                   <groupId>org.springframework.boot</groupId>
                                   <artifactId>spring-boot-maven-plugin</artifactId>
                          </plugin>
                 </plugins>
         </build>
</project>
  
Create a batch configuration class as below.

package com.javainuse.jobs;

import java.util.Date;

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.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.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.annotation.Scheduled;
import com.javainuse.tasklet.FileDeletingTasklet;

@Configuration
@EnableBatchProcessing
public class ProcessMultiFilesJob {
         @Autowired
         private JobBuilderFactory jobBuilderFactory;
         @Autowired
         private StepBuilderFactory stepBuilderFactory;
         @Autowired
         private SimpleJobLauncher jobLauncher;
         @Value("file:C:\\inbox\\")
         private Resource directory;
         @Bean
         public ResourcelessTransactionManager transactionManager() {
                 return new ResourcelessTransactionManager();
         }

         @Bean
         public MapJobRepositoryFactoryBean mapJobRepositoryFactory(ResourcelessTransactionManager txManager)
                          throws Exception {

                 MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(txManager);

                 factory.afterPropertiesSet();

                 return factory;
         }

         @Bean
         public JobRepository jobRepository(MapJobRepositoryFactoryBean factory) throws Exception {
                 return factory.getObject();
         }

         @Scheduled(cron = "*/5 * * * * *")
         public void perform() throws Exception {

                 System.out.println("Job Started at :" + new Date());

                 JobParameters param = new JobParametersBuilder().addString("JobID", String.valueOf(System.currentTimeMillis()))
                                   .toJobParameters();

                 JobExecution execution = jobLauncher.run(readFiles(), param);

                 System.out.println("Job finished with status :" + execution.getStatus());
         }

         @Bean
         public Job readFiles() {
                 return jobBuilderFactory.get("readFiles").incrementer(new RunIdIncrementer()).flow(step1()).end().build();
         }

         @Bean
         public Step step1() {
                 return stepBuilderFactory.get("step1").tasklet(fileDeletingTasklet()).build();
         }

         @Bean
         public FileDeletingTasklet fileDeletingTasklet() {
                 FileDeletingTasklet tasklet = new FileDeletingTasklet();
                 tasklet.setDirectory(directory);
                 return tasklet;
         }

         @Bean
         public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
                 SimpleJobLauncher launcher = new SimpleJobLauncher();
                 launcher.setJobRepository(jobRepository);
                 return launcher;
         }
}
In the above configuration, we get the reference of the configured JobLauncher through autowired injection. Run the JobLauncher with passing job bean and custom job parameter.
Next define the Tasklet as follows-

package com.javainuse.jobs;

import java.util.Date;

import org.springframework.batch.core.Job;
import org.springframework.cbatch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
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.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.annotation.Scheduled;

import com.javainuse.tasklet.FileDeletingTasklet;
@Configuration
@EnableBatchProcessing
public class ProcessMultiFilesJob {
         @Autowired
         private JobBuilderFactory jobBuilderFactory;
         @Autowired
         private StepBuilderFactory stepBuilderFactory;
         @Autowired
         private SimpleJobLauncher jobLauncher;
         @Value("file:C:\\inbox\\")
         private Resource directory;
         @Bean
         public ResourcelessTransactionManager transactionManager() {
                 return new ResourcelessTransactionManager();
         }
         @Bean
         public MapJobRepositoryFactoryBean mapJobRepositoryFactory(ResourcelessTransactionManager txManager)       throws Exception {
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean (txManager);
                 factory.afterPropertiesSet();
                 return factory;
         }

         @Bean
         public JobRepository jobRepository(MapJobRepositoryFactoryBean factory) throws Exception {
                 return factory.getObject();
         }

         @Scheduled(cron = "*/5 * * * * *")
         public void perform() throws Exception {

                 System.out.println("Job Started at :" + new Date());

                 JobParameters param = new JobParametersBuilder().addString("JobID", String.valueOf(System.currentTimeMillis()))
                                   .toJobParameters();

                 JobExecution execution = jobLauncher.run(readFiles(), param);

                 System.out.println("Job finished with status :" + execution.getStatus());
         }

         @Bean
         public Job readFiles() {
         return jobBuilderFactory.get("readFiles").incrementer(new RunIdIncrementer()).flow(step1()).end().build();
         }

         @Bean
         public Step step1() {
                 return stepBuilderFactory.get("step1").tasklet(fileDeletingTasklet()).build();
         }

         @Bean
         public FileDeletingTasklet fileDeletingTasklet() {
                 FileDeletingTasklet tasklet = new FileDeletingTasklet();
                 tasklet.setDirectory(directory);
                 return tasklet;
         }

         @Bean
         public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
                 SimpleJobLauncher launcher = new SimpleJobLauncher();
                 launcher.setJobRepository(jobRepository);
                 return launcher;
         }
}

In the application.properties, add the following property which tells the Spring Boot Application to not start the Batch Job on Application startup. Define the class implementing the spring batch ItemProcessor interface as follows-

spring.batch.job.enabled=false
Run the following Spring Boot class to start our application
package com.javainuse;

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableBatchProcessing
public class SpringBatchApplication {

         public static void main(String[] args) {
                 SpringApplication.run(SpringBatchApplication.class, args);
         }
}

The files from the specified folder location get deleted each time the scheduler runs. In our case every 5 seconds.
Description: boot-23_3




No comments:

Docker Swarn

Docker is a tool intended to make the process of creating, deploying and running applications easier by using container based virtualization...