Spring BootでSpring BatchのTaskletモデルを試す
Spring BootでSpring BatchのChunkモデルを試す というタイトルの通り、Chunkモデルは例示したので、今回はTaskletモデルなバッチの実装例を紹介しようと思います。
読者想定
- Spring BatchのChunkモデルとTaskletモデルの違いがわかっている方
- Spring BatchのTaskletモデルでの最小限の実装例を知りたい方
- JavaConfigを用いたSpring Batchの実装を知りたい方
公式のサンプル
前回のChunkモデルは公式のハンズオンがあったのですが、Taskletモデルには特にそのような記事が見つかりませんでした……
見つけられたら追記します。
今回作る処理
公式のサンプルが無いので、今回は単純にログを出力するだけやってみようと思います。
そのログの部分にバッチとして実行させたい処理を
Spring initializerでひな形作成
Dependenciesには以下を追加
- Lombok
- H2 Database
- Spring Batch
Tasklet, Job, Stepを実装するConfigurationクラスの実装
Config用のクラスを作成(今回は BatchConfiguration
クラス)する。
package com.example.demo.batchprocessing;
import lombok.extern.slf4j.Slf4j;
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.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
@Slf4j
public class BatchConfiguration {
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
/**
* 1つのバッチ処理の処理順やエラーハンドリング等の定義を行う
*
* @return Jobを返却
*/
@Bean
public Job importUserJob() {
return jobBuilderFactory.get("importUserJob")
.incrementer(new RunIdIncrementer())
.flow(step1())
.end()
.build();
}
/**
* Jobの中に含まれるステップを定義する
* バッチ処理もラムダ式内に記述してしまうか、別クラスに分けて書くことも可能
*
* @return ステップを返却する
*/
@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.tasklet((contribution, chunkContext) -> {
log.info("tasklet step");
log.info("ここにバッチ処理を実装する");
return RepeatStatus.FINISHED;
})
.build();
}
}
Batch終了後にSpringApplicationも終了する
これで実装は完成したが、Batch処理が完了してもビルドタスクが止まらないことに気づくと思います。
そこで、main関数でSpringApplicationを呼んでいる箇所に以下関数でくくってあげることで、Batch処理が終了した際に自動的にSpringApplicationも終了してくれるようになります。
package com.example.batchDemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BatchDemoApplication {
public static void main(String[] args) {
- SpringApplication.run(BatchDemoApplication.class, args);
+ System.exit(SpringApplication.exit(SpringApplication.run(BatchDemoApplication.class, args)));
}
}
バッチの実行
ここまで作成し、Spring Bootを起動したタイミングでバッチが走るようになる。
Gradleプロジェクトであれば、 bootRun
タスクでSpring Bootが立ち上がる。
10:18:37: Executing task 'DemoApplication.main()'...
> Task :compileJava UP-TO-DATE
> Task :processResources
> Task :classes
> Task :DemoApplication.main()
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.5.RELEASE)
2020-11-20 10:18:39.663 INFO 10291 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on YukinoMacBook.local with PID 10291 (/Users/yuki/demo/build/classes/java/main started by yuki in /Users/yuki/demo)
2020-11-20 10:18:39.667 INFO 10291 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2020-11-20 10:18:40.901 INFO 10291 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-11-20 10:18:41.271 INFO 10291 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-11-20 10:18:41.426 INFO 10291 --- [ main] o.s.b.c.r.s.JobRepositoryFactoryBean : No database type set, using meta data indicating: H2
2020-11-20 10:18:41.761 INFO 10291 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
2020-11-20 10:18:41.911 INFO 10291 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 3.147 seconds (JVM running for 3.898)
2020-11-20 10:18:41.915 INFO 10291 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: []
2020-11-20 10:18:42.006 INFO 10291 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=importUserJob]] launched with the following parameters: [{run.id=1}]
2020-11-20 10:18:42.082 INFO 10291 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [step1]
2020-11-20 10:18:42.095 INFO 10291 --- [ main] c.e.d.b.BatchConfiguration : tasklet step
2020-11-20 10:18:42.095 INFO 10291 --- [ main] c.e.d.b.BatchConfiguration : ここにバッチ処理を実装する
2020-11-20 10:18:42.107 INFO 10291 --- [ main] o.s.batch.core.step.AbstractStep : Step: [step1] executed in 24ms
2020-11-20 10:18:42.118 INFO 10291 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=importUserJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED] in 62ms
2020-11-20 10:18:42.121 INFO 10291 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2020-11-20 10:18:42.129 INFO 10291 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
BUILD SUCCESSFUL in 4s
3 actionable tasks: 2 executed, 1 up-to-date
10:18:42: Task execution finished 'DemoApplication.main()'.
終わりに
ここまでできたら実際にJARにまとめるなどして、実際にバッチとして使い始めることができます。
Taskletモデル自体は実装は自由にできてしまうので、実装は比較的簡単ですが、それなりのデメリット(中間コミットの概念が基本的には無いなど)もあるうえ、Taskletのみ使うならそもそもSpring Batch使う恩恵があまり無い気がするので、実装しようとしているバッチがChunkモデルで実装できないか吟味した上で適宜Taskletモデルな実装をする方針が良いと思います。
次回のSpring Batchの記事ではもう少し踏み込んだユースケースを紹介しようと思います。
それでわ。