これは、なにをしたくて書いたもの?
Spring BootとSpring Batchを合わせて使っている時の、JobParametersIncrementer
の立ち位置がちょっと気になりまして。
JobParametersIncrementer
JobParametersIncrementer
については、こちらに書かれています。
Configuring and Running a Job / Advanced Meta-Data Usage / JobParametersIncrementer
JobOperator
と関連して説明があり、JobOperator#startNextInstance
メソッドは常に新しいJob
インスタンスを開始することが
書かれています。
the startNextInstance method is worth noting. This method will always start a new instance of a Job.
新しいJobInstance
をトリガーする際に新しい(以前と異なる値の)JobParameters
が必要となるJobLauncher
とは異なり、
startNextInstance
メソッドではJob
に関連付けられたJobParametersIncrementer
を使って新しいJob
のインスタンスを作成することに
なるようです。
Unlike JobLauncher though, which requires a new JobParameters object that will trigger a new JobInstance if the parameters are different from any previous set of parameters, the startNextInstance method will use the JobParametersIncrementer tied to the Job to force the Job to a new instance:
JobParametersIncrementer
にはJobParameters
を返すgetNext(JobParameters)
というメソッドがあります。
JobParametersIncrementer (Spring Batch 4.3.5 API)
JobParametersIncrementer
にJobParameters
が与えられると、必要とされる値をインクリメントして、次のJobParameters
を返します。
The contract of JobParametersIncrementer is that, given a JobParameters object, it will return the 'next' JobParameters object by incrementing any necessary values it may contain.
なにがインクリメントされるのかは、JobParametersIncrementer
によって抽象化されています。
用意されている実装としては、RunIdIncrementer
とDataFieldMaxValueJobParametersIncrementer
があり、自分で実装することもできます。
RunIdIncrementer (Spring Batch 4.3.5 API)
DataFieldMaxValueJobParametersIncrementer (Spring Batch 4.3.5 API)
RunIdIncrementer
はrun.id
というパラメーターを使い、初回は1で開始、それ以降はrun.id
をインクリメントしていきます。
DataFieldMaxValueJobParametersIncrementer
は、Spring JDBCのDataFieldMaxValueIncrementer
を使って…要するに、データベースの
シーケンスに相当する機能を使ったインクリメントを行います。
DataFieldMaxValueIncrementer (Spring Framework 5.3.19 API)
よく使うのは、RunIdIncrementer
ではないかな、と思います。
で、今回はJobParametersIncrementer
とJobParameters
の関係でちょっと気になるところがあるので、動かして確認してみます。
環境
今回の環境は、こちら。
$ java --version openjdk 17.0.3 2022-04-19 OpenJDK Runtime Environment (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1) OpenJDK 64-Bit Server VM (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1, mixed mode, sharing) $ mvn --version Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 17.0.3, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-109-generic", arch: "amd64", family: "unix"
JobRepository
で使用するデータベースは、MySQLとします。
$ mysql --version mysql Ver 8.0.29 for Linux on x86_64 (MySQL Community Server - GPL)
MySQLは、172.17.0.2で動作しているものとします。
プロジェクトを作成する
まずは、Spring Bootプロジェクトを作成します。依存関係は、batch
とmysql
としました。
$ curl -s https://start.spring.io/starter.tgz \ -d bootVersion=2.6.7 \ -d javaVersion=17 \ -d name=batch-jobparameters-incrementer \ -d groupId=org.littlewings \ -d artifactId=batch-jobparameters-incrementer \ -d version=0.0.1-SNAPSHOT \ -d packageName=org.littlewings.spring.batch \ -d dependencies=batch,mysql \ -d baseDir=batch-jobparameters-incrementer | tar zxvf -
作成されたプロジェクト内に移動。
$ cd batch-jobparameters-incrementer
<properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
生成されたソースコードは、削除しておきます。
$ rm src/main/java/org/littlewings/spring/batch/BatchJobparametersIncrementerApplication.java src/test/java/org/littlewings/spring/batch/BatchJobparametersIncrementerApplicationTests.java
では、ソースコードを作成していきます。
ソースコードを作成する
今回のお題に沿って、JobParameters
およびJobParametersIncrementer
を使うアプリケーションを作成していきましょう。
Job
の設定は、こちら。
src/main/java/org/littlewings/spring/batch/JobConfig.java
package org.littlewings.spring.batch; import javax.sql.DataSource; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.jsr.JsrJobParametersConverter; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.core.step.tasklet.Tasklet; 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 public class JobConfig { @Autowired JobBuilderFactory jobBuilderFactory; @Autowired StepBuilderFactory stepBuilderFactory; @Bean public Job withJobParametersIncrementerJob() { return jobBuilderFactory .get("withJobParametersIncrementerJob") //.incrementer(new RunIdIncrementer()) .start(withJobParametersIncrementerStep()) .build(); } @Bean Step withJobParametersIncrementerStep() { return stepBuilderFactory .get("withJobParametersIncrementerStep") .tasklet(jobParametersLoggingTasklet()) .build(); } @Bean @StepScope public Tasklet jobParametersLoggingTasklet() { return (contribution, chunkContext) -> { System.out.println("----- start -----"); chunkContext .getStepContext() .getJobParameters() .entrySet() .forEach(entry -> System.out.printf("parameter: %s = %s%n", entry.getKey(), entry.getValue())); System.out.println("----- end -----"); return RepeatStatus.FINISHED; }; } }
最初は、JobParametersIncrementer
(今回はRunIdIncrementer
を使います)は外しておきます。
@Bean public Job withJobParametersIncrementerJob() { return jobBuilderFactory .get("withJobParametersIncrementerJob") //.incrementer(new RunIdIncrementer()) .start(withJobParametersIncrementerStep()) .build(); }
Step
内の処理は、Tasklet
を使って定義することにしましょう。JobParameters
に含まれているパラメーターを、すべて標準出力に
書き出すだけのTasklet
です。
@Bean @StepScope public Tasklet jobParametersLoggingTasklet() { return (contribution, chunkContext) -> { System.out.println("----- start -----"); chunkContext .getStepContext() .getJobParameters() .entrySet() .forEach(entry -> System.out.printf("parameter: %s = %s%n", entry.getKey(), entry.getValue())); System.out.println("----- end -----"); return RepeatStatus.FINISHED; }; }
main
クラス。
src/main/java/org/littlewings/spring/batch/App.java
package org.littlewings.spring.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class App { public static void main(String... args) { SpringApplication.run(App.class, args); } }
アプリケーションの設定。
src/main/resources/application.properties
spring.datasource.url=jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=UTF-8 spring.datasource.username=kazuhira spring.datasource.password=password spring.batch.jdbc.initialize-schema=always
いったん、ベースの部分はこれで完成です。
JobParametersIncrementerを使わずに動かしてみる
まずは、JobParametersIncrementer
を使わずに動かしてみましょう。
パッケージング。
$ mvn package
最初は引数なしで実行。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
ログ。
2022-05-10 01:21:04.498 INFO 20166 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:21:04.631 INFO 20166 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{}] 2022-05-10 01:21:04.716 INFO 20166 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- ----- end ----- 2022-05-10 01:21:04.789 INFO 20166 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 72ms 2022-05-10 01:21:04.849 INFO 20166 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 180ms
当然ですが、JobParameters
から取得できるパラメーターはありませんし、起動時に指定していないこともログ出力されています。
2022-05-10 01:21:04.631 INFO 20166 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{}] ----- start ----- ----- end -----
再度実行。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
この条件だと、JobParameters
なしのJob
はすでに完了しているので、Job
は実行されずに終了します。
2022-05-10 01:21:34.676 INFO 20230 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:21:34.825 INFO 20230 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{}] 2022-05-10 01:21:34.874 INFO 20230 --- [ main] o.s.batch.core.job.SimpleStepHandler : Step already complete or not restartable, so no action to execute: StepExecution: id=1, version=3, name=withJobParametersIncrementerStep, status=COMPLETED, exitStatus=COMPLETED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-10 01:21:34.898 INFO 20230 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 34ms
次に、パラメーターを指定して実行。2つ指定しました。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-1 param2=value2-1
ログ。
2022-05-10 01:21:59.828 INFO 20304 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-1, param2=value2-1] 2022-05-10 01:21:59.962 INFO 20304 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param1=value1-1, param2=value2-1}] 2022-05-10 01:22:00.041 INFO 20304 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: param1 = value1-1 parameter: param2 = value2-1 ----- end ----- 2022-05-10 01:22:00.127 INFO 20304 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 85ms 2022-05-10 01:22:00.168 INFO 20304 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{param1=value1-1, param2=value2-1}] and the following status: [COMPLETED] in 169ms
指定したJobParameter
2つを認識しています。
2022-05-10 01:21:59.828 INFO 20304 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-1, param2=value2-1] 2022-05-10 01:21:59.962 INFO 20304 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param1=value1-1, param2=value2-1}] 2022-05-10 01:22:00.041 INFO 20304 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: param1 = value1-1 parameter: param2 = value2-1 ----- end -----
JobParameter
をひとつだけにして実行。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param2=value2-2
認識するJobParameter
はひとつになります。
2022-05-10 01:23:01.238 INFO 20390 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param2=value2-2] 2022-05-10 01:23:01.436 INFO 20390 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param2=value2-2}] 2022-05-10 01:23:01.534 INFO 20390 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: param2 = value2-2 ----- end ----- 2022-05-10 01:23:01.623 INFO 20390 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 88ms 2022-05-10 01:23:01.693 INFO 20390 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{param2=value2-2}] and the following status: [COMPLETED] in 199ms
2つ指定した時と、同じJobParameter
をもう1度指定してみましょう。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-1 param2=value2-1
この場合は、実行されずに終了、ではなく例外となるようです。
2022-05-10 01:23:54.373 INFO 20463 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-1, param2=value2-1] 2022-05-10 01:23:54.476 INFO 20463 --- [ main] ConditionEvaluationReportLoggingListener : Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2022-05-10 01:23:54.493 ERROR 20463 --- [ main] o.s.boot.SpringApplication : Application run failed java.lang.IllegalStateException: Failed to execute ApplicationRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:771) ~[spring-boot-2.6.7.jar!/:2.6.7] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:758) ~[spring-boot-2.6.7.jar!/:2.6.7] at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[spring-boot-2.6.7.jar!/:2.6.7] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[spring-boot-2.6.7.jar!/:2.6.7] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.7.jar!/:2.6.7] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={param1=value1-1, param2=value2-1}. If you want to run this job again, change the parameters. at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:139) ~[spring-batch-core-4.3.5.jar!/:4.3.5] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.19.jar!/:5.3.19] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.19.jar!/:5.3.19] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.19.jar!/:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.java:181) ~[spring-batch-core-4.3.5.jar!/:4.3.5] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.19.jar!/:5.3.19] at jdk.proxy2/jdk.proxy2.$Proxy46.createJobExecution(Unknown Source) ~[na:na] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:137) ~[spring-batch-core-4.3.5.jar!/:4.3.5] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.5.jar!/:4.3.5] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.19.jar!/:5.3.19] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.19.jar!/:5.3.19] at jdk.proxy2/jdk.proxy2.$Proxy53.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.6.7.jar!/:2.6.7] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.6.7.jar!/:2.6.7] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.6.7.jar!/:2.6.7] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.6.7.jar!/:2.6.7] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.6.7.jar!/:2.6.7] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:768) ~[spring-boot-2.6.7.jar!/:2.6.7] ... 13 common frames omitted
JobParameter
に指定する名前を変えずに、値だけを変えてみます。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-2 param2=value2-3
これは、問題なく起動できます。
2022-05-10 01:24:46.195 INFO 20540 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-2, param2=value2-3] 2022-05-10 01:24:46.447 INFO 20540 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param1=value1-2, param2=value2-3}] 2022-05-10 01:24:46.582 INFO 20540 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: param1 = value1-2 parameter: param2 = value2-3 ----- end ----- 2022-05-10 01:24:46.679 INFO 20540 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 96ms 2022-05-10 01:24:46.731 INFO 20540 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{param1=value1-2, param2=value2-3}] and the following status: [COMPLETED] in 226ms
このパターンの確認は、ここまでにしておきましょう。
データベースを1度再作成しておきます。
mysql> drop database practice; Query OK, 9 rows affected (0.84 sec) mysql> create database practice; Query OK, 1 row affected (0.08 sec)
JobParametersIncrementerを適用してみる
次は、JobParametersIncrementer
を適用してみます。実装としてはRunIdIncrementer
を使うので、コメントアウトを解除して
@Bean public Job withJobParametersIncrementerJob() { return jobBuilderFactory .get("withJobParametersIncrementerJob") .incrementer(new RunIdIncrementer()) .start(withJobParametersIncrementerStep()) .build(); }
パッケージングします。
$ mvn package
まずはJobParameters
なしで実行。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
ログ。
2022-05-10 01:31:35.871 INFO 21255 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:31:36.029 INFO 21255 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=1}] 2022-05-10 01:31:36.143 INFO 21255 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 1 ----- end ----- 2022-05-10 01:31:36.240 INFO 21255 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 96ms 2022-05-10 01:31:36.291 INFO 21255 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED] in 220ms
起動時に指定していないものの、run.id
というJobParameter
が現れます。
2022-05-10 01:31:35.871 INFO 21255 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:31:36.029 INFO 21255 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=1}] 2022-05-10 01:31:36.143 INFO 21255 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 1 ----- end -----
RunIdIncrementer
は、run.id
というJobParameter
をインクリメントするクラスでした。パラメーターが存在しない場合は、1
に初期化します。
This incrementer increments a "run.id" parameter of type Long from the given job parameters. If the parameter does not exist, it will be initialized to 1.
RunIdIncrementer (Spring Batch 4.3.5 API)
もう1度引数なしで実行してみましょう。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
JobParametersIncrementer
を適用していない時と異なり、今回は起動できます。
2022-05-10 01:32:35.690 INFO 21336 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:32:35.914 INFO 21336 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=2}] 2022-05-10 01:32:36.022 INFO 21336 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 2 ----- end ----- 2022-05-10 01:32:36.117 INFO 21336 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 95ms 2022-05-10 01:32:36.171 INFO 21336 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{run.id=2}] and the following status: [COMPLETED] in 209ms
この時、run.id
の値が2
にインクリメントされています。
この値は、BATCH_JOB_EXECUTION_PARAMS
テーブルに保存されています。
mysql> select * from BATCH_JOB_EXECUTION_PARAMS; +------------------+---------+----------+------------+----------------------------+----------+------------+-------------+ | JOB_EXECUTION_ID | TYPE_CD | KEY_NAME | STRING_VAL | DATE_VAL | LONG_VAL | DOUBLE_VAL | IDENTIFYING | +------------------+---------+----------+------------+----------------------------+----------+------------+-------------+ | 1 | LONG | run.id | | 1970-01-01 09:00:00.000000 | 1 | 0 | Y | | 2 | LONG | run.id | | 1970-01-01 09:00:00.000000 | 2 | 0 | Y | +------------------+---------+----------+------------+----------------------------+----------+------------+-------------+ 2 rows in set (0.00 sec)
次に、JobParameter
を2つ与えて実行。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-1 param2=value2-1
run.id
はインクリメントされつつ、JobParameter
が2つ追加されました。
2022-05-10 01:37:26.677 INFO 21652 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-1, param2=value2-1] 2022-05-10 01:37:26.884 INFO 21652 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=3, param1=value1-1, param2=value2-1}] 2022-05-10 01:37:27.017 INFO 21652 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 3 parameter: param1 = value1-1 parameter: param2 = value2-1 ----- end ----- 2022-05-10 01:37:27.108 INFO 21652 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 90ms 2022-05-10 01:37:27.164 INFO 21652 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{run.id=3, param1=value1-1, param2=value2-1}] and the following status: [COMPLETED] in 226ms
今度は、JobParameter
をひとつ指定して、項目名は同じで値は変更して実行してみます。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param2=value2-2
ログ。
2022-05-10 01:38:12.017 INFO 21743 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param2=value2-2] 2022-05-10 01:38:12.221 INFO 21743 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=4, param1=value1-1, param2=value2-2}] 2022-05-10 01:38:12.343 INFO 21743 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 4 parameter: param1 = value1-1 parameter: param2 = value2-2 ----- end ----- 2022-05-10 01:38:12.448 INFO 21743 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 104ms 2022-05-10 01:38:12.551 INFO 21743 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{run.id=4, param1=value1-1, param2=value2-2}] and the following status: [COMPLETED] in 245ms
よく見ると、起動時に指定したJobParameter
はひとつなのに
2022-05-10 01:38:12.017 INFO 21743 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param2=value2-2]
run.id
以外にも、さらにもうひとつJobParameter
を認識しています。
2022-05-10 01:38:12.221 INFO 21743 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=4, param1=value1-1, param2=value2-2}] 2022-05-10 01:38:12.343 INFO 21743 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 4 parameter: param1 = value1-1 parameter: param2 = value2-2 ----- end -----
この時のBATCH_JOB_EXECUTION_PARAMS
テーブルの内容。
mysql> select * from BATCH_JOB_EXECUTION_PARAMS; +------------------+---------+----------+------------+----------------------------+----------+------------+-------------+ | JOB_EXECUTION_ID | TYPE_CD | KEY_NAME | STRING_VAL | DATE_VAL | LONG_VAL | DOUBLE_VAL | IDENTIFYING | +------------------+---------+----------+------------+----------------------------+----------+------------+-------------+ | 1 | LONG | run.id | | 1970-01-01 09:00:00.000000 | 1 | 0 | Y | | 2 | LONG | run.id | | 1970-01-01 09:00:00.000000 | 2 | 0 | Y | | 3 | LONG | run.id | | 1970-01-01 09:00:00.000000 | 3 | 0 | Y | | 3 | STRING | param1 | value1-1 | 1970-01-01 09:00:00.000000 | 0 | 0 | Y | | 3 | STRING | param2 | value2-1 | 1970-01-01 09:00:00.000000 | 0 | 0 | Y | | 4 | LONG | run.id | | 1970-01-01 09:00:00.000000 | 4 | 0 | Y | | 4 | STRING | param1 | value1-1 | 1970-01-01 09:00:00.000000 | 0 | 0 | Y | | 4 | STRING | param2 | value2-2 | 1970-01-01 09:00:00.000000 | 0 | 0 | Y | +------------------+---------+----------+------------+----------------------------+----------+------------+-------------+ 8 rows in set (0.00 sec)
どうやら、指定しなかったJobParameter
についても、ひとつ前の値を引き継いでいるように見えます。
最初にJobParameter
を2つ指定したパターンと、同じ値を指定してみましょう。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-1 param2=value2-1
JobParametersIncrementer
を適用していない時はこのパターンは例外がスローされましたが、今回は成功します。
2022-05-10 01:40:24.813 INFO 21889 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-1, param2=value2-1] 2022-05-10 01:40:25.008 INFO 21889 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=5, param1=value1-1, param2=value2-1}] 2022-05-10 01:40:25.102 INFO 21889 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 5 parameter: param1 = value1-1 parameter: param2 = value2-1 ----- end ----- 2022-05-10 01:40:25.179 INFO 21889 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 77ms 2022-05-10 01:40:25.230 INFO 21889 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{run.id=5, param1=value1-1, param2=value2-1}] and the following status: [COMPLETED] in 171ms
値を変えてみます。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-2 param2=value2-3
こちらもうまくいきます。
2022-05-10 01:41:23.113 INFO 22000 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-2, param2=value2-3] 2022-05-10 01:41:23.327 INFO 22000 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=6, param1=value1-2, param2=value2-3}] 2022-05-10 01:41:23.445 INFO 22000 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 6 parameter: param1 = value1-2 parameter: param2 = value2-3 ----- end ----- 2022-05-10 01:41:23.570 INFO 22000 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 124ms 2022-05-10 01:41:23.644 INFO 22000 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{run.id=6, param1=value1-2, param2=value2-3}] and the following status: [COMPLETED] in 251ms
最後に、JobParameter
指定なしに戻してみましょう。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
すると、やっぱりひとつ前に指定したJobParameter
の内容を復元してきます。
2022-05-10 01:42:16.446 INFO 22086 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:42:16.623 INFO 22086 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{run.id=7, param1=value1-2, param2=value2-3}] 2022-05-10 01:42:16.734 INFO 22086 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: run.id = 7 parameter: param1 = value1-2 parameter: param2 = value2-3 ----- end ----- 2022-05-10 01:42:16.813 INFO 22086 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 79ms 2022-05-10 01:42:16.874 INFO 22086 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{run.id=7, param1=value1-2, param2=value2-3}] and the following status: [COMPLETED] in 210ms
動作を見ていると、1度でもJobParameter
を指定すると、次回の実行時にはその値を復元し、明示的に与えた場合は上書きして実行している
ように見えますね。
ここで、Spring BootのSpring Batchに関するドキュメントを見てみます。
バッチの実行は、JobLauncherApplicationRunner
で行われると書かれています。
By default, it executes all Jobs in the application context on startup (see JobLauncherApplicationRunner for details).
“How-to” Guides / Batch Applications / Running Spring Batch Jobs on Startup
ここでJobLauncherApplicationRunner
のソースコードを見ると、JobParametersIncrementer
が指定されている場合は、JobParameters
を
起動時に明示的に与えたものと過去の値をマージして実行しているようです。
他のSpring BatchのJob
の起動方法は今回は見ませんが、JobParametersIncrementer
自体が「次回のJobParameters
」を作成するもの
という扱いだったので、そもそもそういうものかもしれません…。
The contract of JobParametersIncrementer is that, given a JobParameters object, it will return the 'next' JobParameters object by incrementing any necessary values it may contain.
Configuring and Running a Job / Advanced Meta-Data Usage / JobParametersIncrementer
このようにJobParametersIncrementer
を使用すると、JobParameter
をインクリメントしてJob
を実行できるようになるものの、
JobParameters
自体の扱いは少し変わってしまうことがわかりました。
JsrJobParametersConverterを試してみる
ところで、RunIdIncrementer
を使うとrun.id
をインクリメントしてJob
を実行できるのですが、JobParametersIncrementer
ではないものの
似たような機能を持つJsrJobParametersConverter
というものがあったので、こちらも試してみます。
RunIdIncrementer
を使うのをやめて、
@Bean public Job withJobParametersIncrementerJob() { return jobBuilderFactory .get("withJobParametersIncrementerJob") //.incrementer(new RunIdIncrementer()) .start(withJobParametersIncrementerStep()) .build(); }
JsrJobParametersConverter
をBeanとして定義します。
@Bean public JobParametersConverter jobParametersConverter(DataSource dataSource) { return new JsrJobParametersConverter(dataSource); }
データベースを再作成。
mysql> drop database practice; Query OK, 9 rows affected (0.43 sec) mysql> create database practice; Query OK, 1 row affected (0.03 sec)
パッケージング。
$ mvn package
ここからは、JobParametersIncrementer
(RunIdIncrementer
)を指定した時と同じパターンを実行していってみます。
まずは、JobParameter
指定なしの場合。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
ログ。
2022-05-10 01:53:09.280 INFO 22945 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:53:09.457 INFO 22945 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{jsr_batch_run_id=1}] 2022-05-10 01:53:09.592 INFO 22945 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 1 ----- end ----- 2022-05-10 01:53:09.680 INFO 22945 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 88ms 2022-05-10 01:53:09.765 INFO 22945 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED] in 237ms
JobParametersIncrementer
(RunIdIncrementer
)を指定した時はrun.id
だったのがjsr_batch_run_id
になりましたが、似たような動きをしているように見えます。
2022-05-10 01:53:09.280 INFO 22945 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:53:09.457 INFO 22945 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{jsr_batch_run_id=1}] 2022-05-10 01:53:09.592 INFO 22945 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 1 ----- end -----
もう1度実行してみましょう。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
jsr_batch_run_id
がインクリメントされました。
2022-05-10 01:53:37.420 INFO 23002 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:53:37.638 INFO 23002 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{jsr_batch_run_id=3}] 2022-05-10 01:53:37.741 INFO 23002 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 3 ----- end ----- 2022-05-10 01:53:37.831 INFO 23002 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 89ms 2022-05-10 01:53:37.905 INFO 23002 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{jsr_batch_run_id=3}] and the following status: [COMPLETED] in 202ms
なのですが、なぜか飛び番になっていますね…。これはまた後で…。
JobParameter
を指定。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-1 param2=value2-1
JobParameter
が追加されつつ、jsr_batch_run_id
がインクリメントされています。飛び番になっていますが。
2022-05-10 01:54:05.861 INFO 23096 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-1, param2=value2-1] 2022-05-10 01:54:06.070 INFO 23096 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param1=value1-1, param2=value2-1, jsr_batch_run_id=5}] 2022-05-10 01:54:06.165 INFO 23096 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 5 parameter: param1 = value1-1 parameter: param2 = value2-1 ----- end ----- 2022-05-10 01:54:06.266 INFO 23096 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 101ms 2022-05-10 01:54:06.329 INFO 23096 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{param1=value1-1, param2=value2-1, jsr_batch_run_id=5}] and the following status: [COMPLETED] in 207ms
JobParameter
を減らしつつ、値を変更。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param2=value2-2
すると、JobParametersIncrementer
(RunIdIncrementer
)を使っていた時には復元されていた前回実行時に指定したJobParameter
が、
今回は復元されません。
2022-05-10 01:54:23.120 INFO 23147 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param2=value2-2] 2022-05-10 01:54:23.262 INFO 23147 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param2=value2-2, jsr_batch_run_id=7}] 2022-05-10 01:54:23.354 INFO 23147 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 7 parameter: param2 = value2-2 ----- end ----- 2022-05-10 01:54:23.439 INFO 23147 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 85ms 2022-05-10 01:54:23.487 INFO 23147 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{param2=value2-2, jsr_batch_run_id=7}] and the following status: [COMPLETED] in 185ms
コマンドラインで指定したものだけになっていますね。
----- start ----- parameter: jsr_batch_run_id = 7 parameter: param2 = value2-2 ----- end -----
最初にJobParameter
を指定した時と、同じ値にして実行。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-1 param2=value2-1
こちらも動作します。
2022-05-10 01:54:41.074 INFO 23207 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-1, param2=value2-1] 2022-05-10 01:54:41.250 INFO 23207 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param1=value1-1, param2=value2-1, jsr_batch_run_id=9}] 2022-05-10 01:54:41.371 INFO 23207 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 9 parameter: param1 = value1-1 parameter: param2 = value2-1 ----- end ----- 2022-05-10 01:54:41.454 INFO 23207 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 82ms 2022-05-10 01:54:41.498 INFO 23207 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{param1=value1-1, param2=value2-1, jsr_batch_run_id=9}] and the following status: [COMPLETED] in 202ms
指定する値を変えてみます。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar param1=value1-2 param2=value2-3
こちらもOKですね。
2022-05-10 01:55:01.612 INFO 23283 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [param1=value1-2, param2=value2-3] 2022-05-10 01:55:01.837 INFO 23283 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{param1=value1-2, param2=value2-3, jsr_batch_run_id=11}] 2022-05-10 01:55:01.935 INFO 23283 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 11 parameter: param1 = value1-2 parameter: param2 = value2-3 ----- end ----- 2022-05-10 01:55:02.050 INFO 23283 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 115ms 2022-05-10 01:55:02.112 INFO 23283 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{param1=value1-2, param2=value2-3, jsr_batch_run_id=11}] and the following status: [COMPLETED] in 229ms
最後に、JobParameter
の指定をなくしてみます。
$ java -Dspring.batch.job.names=withJobParametersIncrementerJob -jar target/batch-jobparameters-incrementer-0.0.1-SNAPSHOT.jar
jsr_batch_run_id
だけが存在することになりました。
2022-05-10 01:55:22.130 INFO 23339 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-10 01:55:22.283 INFO 23339 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] launched with the following parameters: [{jsr_batch_run_id=13}] 2022-05-10 01:55:22.372 INFO 23339 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [withJobParametersIncrementerStep] ----- start ----- parameter: jsr_batch_run_id = 13 ----- end ----- 2022-05-10 01:55:22.523 INFO 23339 --- [ main] o.s.batch.core.step.AbstractStep : Step: [withJobParametersIncrementerStep] executed in 151ms 2022-05-10 01:55:22.614 INFO 23339 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=withJobParametersIncrementerJob]] completed with the following parameters: [{jsr_batch_run_id=13}] and the following status: [COMPLETED] in 253ms
割とわかりやすい動作になっているのではないでしょうか。
さて、インクリメントの仕組みはどのようになっているのでしょうか。ソースコードを少し見てみます。
実際にインクリメントしているのは、こちら。Job
の起動時にJobParameter
としてjsr_batch_run_id
が与えられていない場合は、
インクリメントするようです。
内部ではDataFieldMaxValueIncrementer
を使用しますが、今回はMySQLを使用しているので実際に使われるのはこちらですね。
以下のテーブルを使って実現しています。
mysql> select * from BATCH_JOB_SEQ; +----+------------+ | ID | UNIQUE_KEY | +----+------------+ | 14 | 0 | +----+------------+ 1 row in set (0.00 sec)
ところで、なぜ飛び番になったのか、という点についてですが。
Job
の起動時にjsr_batch_run_id
をインクリメントするために更新する以外にも、ここでカウントアップするからですね。
なので、JsrJobParametersConverter
を使った場合は結果的に1回の実行でBATCH_JOB_SEQ
テーブルの値が2回インクリメントされることに
なります。
これが、飛び番になった理由です。
まあそれくらいならいいかなと思いきや、JSR-356(jBatch)に関するSpring Batchの実装は、次のバージョンで削除されるようです。
Remove JSR-352 implementation · Issue #3894 · spring-projects/spring-batch · GitHub
Remove JSR-352 implementation · spring-projects/spring-batch@e5c752b · GitHub
この削除対象にJsrJobParametersConverter
も含まれているので、使っている場合はSpring Batch 5.0になったら使えなくなることに
なります。
こちらのissueや参照されているMLを見ると、jBatchがCDIを要求するようになるので、Spring BatchではJSR-352への対応をやめるみたいですね。
まあ、現時点で使うならこの状況を承知のうえで、と…。
まとめ
今回は、Spring Boot(に含まれるJobLauncherApplicationRunner
)を使ってSpring Batchを実行する際に、JobParametersIncrementer
を
使用するとJobParameter
に関する動作がどう変わるのか、ということを確認してみました。
こういう挙動になるとは知らなかったので、ちょっと驚きましたが押さえておくとしましょう。
最後に、RunIdIncrementer
を解除してJsrJobParametersConverter
を使用した、Job
の定義全体を載せておきます。
src/main/java/org/littlewings/spring/batch/JobConfig.java
package org.littlewings.spring.batch; import javax.sql.DataSource; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.jsr.JsrJobParametersConverter; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.core.step.tasklet.Tasklet; 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 public class JobConfig { @Autowired JobBuilderFactory jobBuilderFactory; @Autowired StepBuilderFactory stepBuilderFactory; @Bean public Job withJobParametersIncrementerJob() { return jobBuilderFactory .get("withJobParametersIncrementerJob") //.incrementer(new RunIdIncrementer()) .start(withJobParametersIncrementerStep()) .build(); } @Bean Step withJobParametersIncrementerStep() { return stepBuilderFactory .get("withJobParametersIncrementerStep") .tasklet(jobParametersLoggingTasklet()) .build(); } @Bean @StepScope public Tasklet jobParametersLoggingTasklet() { return (contribution, chunkContext) -> { System.out.println("----- start -----"); chunkContext .getStepContext() .getJobParameters() .entrySet() .forEach(entry -> System.out.printf("parameter: %s = %s%n", entry.getKey(), entry.getValue())); System.out.println("----- end -----"); return RepeatStatus.FINISHED; }; } @Bean public JobParametersConverter jobParametersConverter(DataSource dataSource) { return new JsrJobParametersConverter(dataSource); } }