1. What is a Spring Batch Tasklet?

In Spring batch, a Tasklet is an interface that performs a single task within a Step. A typical use case for implementing a Tasklet is the setup up or cleaning of resources before or after the execution of a Step.

In fact, Spring Batch offers two different ways for implementing a step of a batch job: using Chunks or using a Tasklet.

In the Spring Batch Job example, we saw that a batch job consists out of one or more Steps. And a Tasklet represents the work that is done in a Step.

The Tasklet interface has one method: execute(). A Step calls this method repeatedly until it either finishes or throws an exception.

The Spring Batch framework contains some implementations of the Tasklet interface. One of them is a “chunk oriented processing” Tasklet. If you look at the ChunkOrientedTasklet you can see it implements the Tasklet interface.

So let’s recap the above:

Question

Answer

When do I use a Tasklet?

When you need to execute a single granular task.

How does a Tasklet work?

Everything happens within a single transaction boundary that either finishes or throws an error.

Is a Tasklet often used?

It is not used very often. In most cases, you will use chunks to handle large volumes.

What is a typical Tasklet use case?

Usually used to setup up or clean resources before or after the main processing.

To show you how a Spring Batch Tasklet works let’s create a simple example.

4. Unit Test the Spring Batch Tasklet

Let’s update the existing unit test case so that we can check if our file deleting Tasklet works.

First, we copy the input files to the location from which our batch job will read. This is done in the copyFiles() method before the test case runs using the @Before annotation.

We then launch the batch job and check if it finishes successfully. We also check if all input files have been deleted.

packagecom.codenotfound.batch;importstaticorg.assertj.core.api.Assertions.assertThat;importjava.io.File;importjava.io.IOException;importjava.net.URISyntaxException;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.Paths;importorg.junit.BeforeClass;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.batch.core.Job;importorg.springframework.batch.core.JobExecution;importorg.springframework.batch.core.launch.NoSuchJobException;importorg.springframework.batch.test.JobLauncherTestUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.Import;importorg.springframework.core.io.ClassPathResource;importorg.springframework.test.context.junit4.SpringRunner;importorg.springframework.util.FileSystemUtils;importcom.codenotfound.batch.job.BatchConfig;importcom.codenotfound.batch.job.CapitalizeNamesJobConfig;@RunWith(SpringRunner.class)@SpringBootTest(classes={SpringBatchApplicationTests.BatchTestConfig.class})publicclassSpringBatchApplicationTests{privatestaticPathcsvFilesPath,testInputsPath;@AutowiredprivateJobLauncherTestUtilsjobLauncherTestUtils;@BeforeClasspublicstaticvoidcopyFiles()throwsURISyntaxException,IOException{csvFilesPath=Paths.get(newClassPathResource("csv").getURI());testInputsPath=Paths.get("target/test-inputs");try{Files.createDirectory(testInputsPath);}catch(Exceptione){// if directory exists do nothing}FileSystemUtils.copyRecursively(csvFilesPath,testInputsPath);}@TestpublicvoidtestHelloWorldJob()throwsException{JobExecutionjobExecution=jobLauncherTestUtils.launchJob();assertThat(jobExecution.getExitStatus().getExitCode()).isEqualTo("COMPLETED");// check that all files are deletedFiletestInput=testInputsPath.toFile();assertThat(testInput.list().length).isEqualTo(0);}@Configuration@Import({BatchConfig.class,CapitalizeNamesJobConfig.class})staticclassBatchTestConfig{@AutowiredprivateJobcapitalizeNamesJob;@BeanJobLauncherTestUtilsjobLauncherTestUtils()throwsNoSuchJobException{JobLauncherTestUtilsjobLauncherTestUtils=newJobLauncherTestUtils();jobLauncherTestUtils.setJob(capitalizeNamesJob);returnjobLauncherTestUtils;}}}

Now run above test case. Open a command prompt and execute following Maven command:

mvn test

Maven will download the needed dependencies, compile the code and run the unit test case. The result should be a successful build as shown below: