1. Concepts of Job, Step, Tasklet You should know one basic concept of them. that is one of the relationship between each them.
‘Job’ includes ‘Step’
‘Step’ includes ‘Tasklet’
so You can remember the relationship between them like the below.
Job
It’s like a container for Step.
It represents the one time of batch processing.
Step
It’s the object has components that is needed to batch processing.
It’s actual used component when the batch system is operated.
Tasklet
Tasklet can have the business logic what you want to do. so what i’m saying is you just type your code in there.
2. Let’s build simple spring batch with Tasklet.
add dependencies to process spring batch.
1 2 3 4 5 6 7 8 9 10 11 12 13 implementation 'org.springframework.boot:spring-boot-starter-batch' implementation 'com.h2database:h2:1.4.197' compileOnly 'org.projectlombok:lombok' testCompileOnly 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' annotationProcessor 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok'
turn on batch processing with @EnableBatchProcessing annotation.
1 2 3 4 5 6 7 8 9 @EnableBatchProcessing @SpringBootApplication public class BatchExampleApplication { public static void main (String[] args) { SpringApplication.run(BatchExampleApplication.class, args); } }
create custom Tasklet has the business logics you want.
1 2 3 4 5 6 7 8 @Slf4j public class SampleTasklet implements Tasklet { @Override public RepeatStatus execute (StepContribution contribution, ChunkContext chunkContext) throws Exception { log.info("executed tasklet !!" ); return RepeatStatus.FINISHED; } }
Basically, You should create job , step to operate batch processing. the below code is for that. as you can see, job includes step and step includes tasklet .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Configuration @RequiredArgsConstructor public class SampleConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; @Bean public Job sampleJob () { return jobBuilderFactory.get("sampleJob" ) .start(sampleStep()) .build(); } @Bean public Step sampleStep () { return stepBuilderFactory.get("sampleStep" ) .tasklet(new SampleTasklet ()) .build(); } }
1 2 3 4 5 6 7 2022-01-24 10:24:57.075 INFO 12160 --- [ main] c.k.y.b.BatchExampleApplication : Started BatchExampleApplication in 0.907 seconds (JVM running for 1.273) 2022-01-24 10:24:57.076 INFO 12160 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-01-24 10:24:57.123 INFO 12160 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=sampleJob]] launched with the following parameters: [{}] 2022-01-24 10:24:57.142 INFO 12160 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [sampleStep] 2022-01-24 10:24:57.147 INFO 12160 --- [ main] c.kian.yun.batch_example.SampleTasklet : executed tasklet !! 2022-01-24 10:24:57.151 INFO 12160 --- [ main] o.s.batch.core.step.AbstractStep : Step: [sampleStep] executed in 8ms 2022-01-24 10:24:57.154 INFO 12160 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=sampleJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 18ms
you can see the log created in SampleTasklet at the console.
3. the three ways to implement Tasklet. as you see before, the first way is that creating sub class of Tasklet class like SampleTasklet .
1 2 3 4 5 6 7 public class SampleTasklet implements Tasklet { @Override public RepeatStatus execute (StepContribution contribution, ChunkContext chunkContext) throws Exception { log.info("executed tasklet !!" ); return RepeatStatus.FINISHED; } }
second way is the best simple one. It is that you create sub class of Tasklet with lambda expression.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Configuration @RequiredArgsConstructor public class SampleConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; @Bean public Job lambdaJob () { return jobBuilderFactory.get("lambdaJob" ) .start(lambdaStep()) .build(); } @Bean public Step lambdaStep () { return stepBuilderFactory.get("lambdaStep" ) .tasklet((contribution, chunkContext) -> { log.info("executed tasklet created by lambda !!" ); return RepeatStatus.FINISHED; }).build(); } }
Last way would able to use the special case like you need the function is included at other service.
1 2 3 4 5 public class OtherService { public void businessLogic () { log.info("executed Tasklet in OtherService.businessLogic !!" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Configuration @RequiredArgsConstructor public class SampleConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; @Bean public Job invokedJob () { return jobBuilderFactory.get("invokedJob" ) .start(invokedStep()) .build(); } @Bean public Step invokedStep () { return stepBuilderFactory.get("invokedStep" ) .tasklet(invokedTasklet()) .build(); } @Bean public OtherService otherService () { return new OtherService (); } @Bean public MethodInvokingTaskletAdapter invokedTasklet () { MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter (); adapter.setTargetObject(otherService()); adapter.setTargetMethod("businessLogic" ); return adapter; } }
Spring batch offers the service that can control batch execution by the condition of other each step status.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 @Configuration @RequiredArgsConstructor public class SampleConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; @Bean public Job flowJob () { return jobBuilderFactory.get("flowJob" ) .start(conditionStep()) .on("COMPLETED" ) .to(completedStep()) .on("*" ) .end() .from(conditionStep()) .on("FAILED" ) .to(failedStep()) .on("*" ) .end() .end().build(); } @Bean public Step conditionStep () { return stepBuilderFactory.get("conditionStep" ) .tasklet((contribution, chunkContext) -> { log.info("condition step !!" ); contribution.setExitStatus(ExitStatus.COMPLETED); return RepeatStatus.FINISHED; }).build(); } @Bean public Step completedStep () { return stepBuilderFactory.get("completedStep" ) .tasklet((contribution, chunkContext) -> { log.info("completed step !!" ); return RepeatStatus.FINISHED; }).build(); } @Bean public Step failedStep () { return stepBuilderFactory.get("failedStep" ) .tasklet((contribution, chunkContext) -> { log.info("failed step !!" ); return RepeatStatus.FINISHED; }).build(); } }
5. About Chunk