バッチアプリケーションのBean定義の構成
Macchinetta Batch Framework (2.x)のバッチアプリケーションでは、Bean定義をもちいて各種設定を行う。
Spring Frameworkや、Spring Batchをはじめとする、様々なOSSを基盤としているフレームワークであるMacchinetta Batch Framework (2.x)は、Bean定義で設定できる機能も多岐に及び、これらのOSSに対する設定を行う、Bean定義も複雑なものになりやすい。
Macchinetta Batch Framework (2.x)では、Bean定義の複雑さを緩和し、管理が行いやすくなるように、役割ごとにBean定義ファイルを作成することを想定している。本ガイドラインで想定するBean定義の分類は以下の通りである。
分類 | 役割 | 開発者のやること |
---|---|---|
アプリケーション全体のBean定義 |
アプリケーション全体で共通する設定をここにまとめる。これによってジョブ定義間の設定の重複を抑止する。 |
カスタマイズ(必要な場合) |
ジョブのBean定義 |
業務要件にもとづくバッチ処理の定義をここにまとめる。 |
新規作成 |
非同期バッチデーモンのBean定義 |
非同期処理をおこなう場合の定義をここにまとめる。 |
カスタマイズ(必要な場合) |
各Bean定義とBean定義ファイルの関係は、Bean定義の分類とBean定義ファイルの対応関係を参照のこと。
開発者がいちから作成するのはジョブのBean定義のみである。
ブランクプロジェクト(後述)では、アプリケーション全体のBean定義、非同期バッチデーモンのBean定義の定義ファイルを、初期設定済みの状態で提供する。これらは必要なときのみカスタマイズすればよい。
各Bean定義で記述する設定の詳細は、以降で説明する。
アプリケーション全体のBean定義
代表的な設定内容としては主に以下がある。
-
Macchinetta Batch Framework (2.x)を構成するOSSスタックの初期設定
-
Spring Batchの挙動設定(トランザクションの設定など)
-
MyBatis3の挙動設定(データソースからのフェッチサイズのチューニングなど)
-
-
上記以外の複数のジョブに共通する設定
-
入力チェック用バリデータの設定
-
メッセージファイルの設定
-
このBean定義は、他のBean定義(ジョブのBean定義、非同期バッチデーモンのBean定義)から参照される。
詳細はアプリケーション全体の設定のこと。
非同期バッチデーモンのBean定義
非同期バッチデーモンの起動設定を行う。
Macchinetta Batch Framework (2.x)では、ジョブの非同期実行が可能である。テーブルに登録されているジョブの情報を監視し、非同期でジョブを起動するモジュールを非同期バッチデーモンという。
詳細は非同期実行(DBポーリング)を参照のこと。
Bean定義の記述方法
Macchinetta Batch Framework (2.x)では、Bean定義の記述方法としてJavaConfig または XMLConfig のいずれかを選択することができる。
JavaConfig/XMLConfigの説明の併記
以降、説明対象が同じであるがBean定義の媒体が異なる場合、JavaConfig/XMLConfigという形式で併記する。また、JavaConfig/XMLConfigで異なる説明が必要な箇所では、タブ切り替えを用いる。 |
Springの各種OSSにおけるリファレンスドキュメントでは、コード例の提示がJavaConfigしかないケースが増えているため、開発元からの正式なアナウンスは現状ないものの、今後はSpring全体として、XMLConfigよりもJavaConfigにより注力すると考えられる。
Bean定義の分類とBean定義ファイルの対応関係
各Bean定義の分類と、ブランクプロジェクトのBean定義ファイルとの関係は以下の通り。
Bean定義の分類 | Bean定義ファイル(JavaConfig) | Bean定義ファイル(XMLConfig) |
---|---|---|
アプリケーション全体のBean定義 |
JobBaseContextConfig.java |
job-base-context.xml |
ジョブのBean定義 |
Job01Config.java |
job01.xml |
非同期バッチデーモンのBean定義 |
AsyncBatchDaemonConfig.java |
async-batch-daemon.xml |
上表からも明らかなように、JavaConfigのTerasolunaBatchConfiguration.java
に相当するBean定義ファイルがXMLConfigには存在しない。この理由は、Spring Batchから提供される、Bean定義をサポートする仕組み(DefaultBatchConfiguration
)が、JavaConfig向けにしかないためである。
DefaultBatchConfiguration
の詳細は、AppendixのDefaultBatchConfigurationを参照のこと。
Macchinetta Batch Framework (2.x)では、DefaultBatchConfiguration
を直接使用せず、その継承クラスTerasolunaBatchConfiguration
を使用する。これは、Macchinetta Batch Framework (2.x)の動作上、DefaultBatchConfiguration
の一部のBean定義のカスタマイズが必須となるためである。
TerasolunaBatchConfiguration
の詳細は、AppendixのTerasolunaBatchConfigurationを参照のこと。
ブランクプロジェクトとは
ブランクプロジェクトとは、各Bean定義(アプリケーション全体のBean定義、ジョブのBean定義(サンプル)、非同期バッチデーモンのBean定義)をあらかじめ行った開発プロジェクトの雛形であり、
アプリケーション開発のスタート地点である。
本ガイドラインでは、シングルプロジェクト構成のブランクプロジェクトを提供する。
構成の説明については、プロジェクトの構成を参照。
Macchinetta Server 1.xとの違い
Macchinetta Server 1.xはマルチプロジェクト構成を推奨している。 この理由は主に、以下の様なメリットを享受するためである。
しかし、本ガイドラインではMacchinetta Server 1.xと異なりシングルプロジェクト構成としている。 これは、前述の点はバッチアプリケーションの場合においても考慮すべきだが、
シングルプロジェクト構成にすることで1ジョブに関連する資材を近づけることを優先している。 |
プロジェクトの作成
Maven Archetype Plugin
のarchetype:generate
を使用して、プロジェクトを作成する方法を説明する。
作成環境の前提について
以下を前提とし説明する。
|
プロジェクトを作成するディレクトリにて、以下のコマンドを実行する。
archetypeArtifactId
にmacchinetta-batch-archetype
を指定
下記のバージョン識別子は 2.5.0.RELEASE に一部ファイルの誤配置があったため、修正した 2.5.0.1.RELEASE を指定している。
|
C:\xxx>mvn archetype:generate ^
-DarchetypeGroupId=com.github.macchinetta.blank ^
-DarchetypeArtifactId=macchinetta-batch-archetype ^
-DarchetypeVersion=2.5.0.1.RELEASE
$ mvn archetype:generate \
-DarchetypeGroupId=com.github.macchinetta.blank \
-DarchetypeArtifactId=macchinetta-batch-archetype \
-DarchetypeVersion=2.5.0.1.RELEASE
archetypeArtifactId
にmacchinetta-batch-xmlconfig-archetype
を指定
下記のバージョン識別子は、JavaConfig版の変更に併せて 2.5.0.1.RELEASE を指定しているが、XMLConfig版は2.5.0.RELEASE と内容は同一である。 |
C:\xxx>mvn archetype:generate ^
-DarchetypeGroupId=com.github.macchinetta.blank ^
-DarchetypeArtifactId=macchinetta-batch-xmlconfig-archetype ^
-DarchetypeVersion=2.5.0.1.RELEASE
$ mvn archetype:generate \
-DarchetypeGroupId=com.github.macchinetta.blank \
-DarchetypeArtifactId=macchinetta-batch-xmlconfig-archetype \
-DarchetypeVersion=2.5.0.1.RELEASE
その後、利用者の状況に合わせて、以下を対話式に設定する。
-
groupId
-
artifactId
-
version
-
package
以下の値を設定し実行した例を示す。
項目名 | 設定例 |
---|---|
groupId |
com.example.batch |
artifactId |
batch |
version |
1.0.0-SNAPSHOT |
package |
com.example.batch |
C:\xxx>mvn archetype:generate ^
More? -DarchetypeGroupId=com.github.macchinetta.blank ^
More? -DarchetypeArtifactId=macchinetta-batch-archetype ^
More? -DarchetypeVersion=2.5.0.1.RELEASE
[INFO] Scanning for projects…
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
(.. omitted)
Define value for property 'groupId': com.example.batch
Define value for property 'artifactId': batch
Define value for property 'version' 1.0-SNAPSHOT: : 1.0.0-SNAPSHOT
Define value for property 'package' com.example.batch: :
Confirm properties configuration:
groupId: com.example.batch
artifactId: batch
version: 1.0.0-SNAPSHOT
package: com.example.batch
Y: : y
[INFO] ------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: macchinetta-batch-archetype:2.5.0.1.RELEASE
[INFO] ------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.example.batch
[INFO] Parameter: artifactId, Value: batch
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: package, Value: com.example.batch
[INFO] Parameter: packageInPathFormat, Value: com/example/batch
[INFO] Parameter: package, Value: com.example.batch
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: groupId, Value: com.example.batch
[INFO] Parameter: artifactId, Value: batch
[INFO] Project created from Archetype in dir: C:\xxx\batch
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:02 min
[INFO] Finished at: 2019-09-03T09:24:55+09:00
[INFO] Final Memory: 13M/89M
[INFO] ------------------------------------------------------------------------
$ mvn archetype:generate \
> -DarchetypeGroupId=com.github.macchinetta.blank \
> -DarchetypeArtifactId=macchinetta-batch-archetype \
> -DarchetypeVersion=2.5.0.1.RELEASE
[INFO] Scanning for projects…
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
(.. omitted)
Define value for property 'groupId': com.example.batch
Define value for property 'artifactId': batch
Define value for property 'version' 1.0-SNAPSHOT: : 1.0.0-SNAPSHOT
Define value for property 'package' com.example.batch: :
Confirm properties configuration:
groupId: com.example.batch
artifactId: batch
version: 1.0.0-SNAPSHOT
package: com.example.batch
Y: : y
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: macchinetta-batch-archetype:2.5.0.1.RELEASE
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.example.batch
[INFO] Parameter: artifactId, Value: batch
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: package, Value: com.example.batch
[INFO] Parameter: packageInPathFormat, Value: com/example/batch
[INFO] Parameter: package, Value: com.example.batch
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: groupId, Value: com.example.batch
[INFO] Parameter: artifactId, Value: batch
[INFO] Project created from Archetype in dir: C:\xxx\batch
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:46 min
[INFO] Finished at: 2019-09-03T02:39:57+00:00
[INFO] Final Memory: 15M/179M
[INFO] ------------------------------------------------------------------------
以上により、プロジェクトの作成が完了した。
正しく作成出来たかどうかは、ブランクプロジェクトに同梱されているサンプルジョブ(job01
)を以下の要領で実行することで確認できる。
C:\xxx>cd batch
C:\xxx\batch>mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
C:\xxx\batch>java -cp "lib/*;target/*" ^
org.springframework.batch.core.launch.support.CommandLineJobRunner ^
com.example.batch.jobs.Job01Config job01
$ cd batch
$ mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
$ java -cp 'lib/*:target/*' \
org.springframework.batch.core.launch.support.CommandLineJobRunner \
com.example.batch.jobs.Job01Config job01
以下が確認出来れば、プロジェクトの作成は成功である。
-
C:\xxx\batch\target
配下にoutput.csv
が作成されていること。 -
標準出力に
following status: [COMPLETED]
が表示されていること(以下例)。
C:\xxx\batch>mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Macchinetta Batch Framework (2.x) Blank Project 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(.. omitted)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 56.497 s
[INFO] Finished at: 2019-09-03T10:39:59+09:00
[INFO] Final Memory: 25M/145M
[INFO] ------------------------------------------------------------------------
C:\xxx\batch>java -cp "lib/*;target/*" ^
More? org.springframework.batch.core.launch.support.CommandLineJobRunner ^
More? com.example.batch.jobs.Job01Config job01
(.. omitted)
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 10:41:24] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
$ mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Macchinetta Batch Framework (2.x) Blank Project 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(.. omitted)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:39 min
[INFO] Finished at: 2019-09-03T02:43:01+00:00
[INFO] Final Memory: 27M/189M
[INFO] ------------------------------------------------------------------------
$ java -cp 'lib/*:target/*' \
> org.springframework.batch.core.launch.support.CommandLineJobRunner \
> com.example.batch.jobs.Job01Config job01
(.. omitted)
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 02:43:11] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
C:\xxx>cd batch
C:\xxx\batch>mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
C:\xxx\batch>java -cp "lib/*;target/*" ^
org.springframework.batch.core.launch.support.CommandLineJobRunner ^
META-INF/jobs/job01.xml job01
$ cd batch
$ mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
$ java -cp 'lib/*:target/*' \
org.springframework.batch.core.launch.support.CommandLineJobRunner \
META-INF/jobs/job01.xml job01
以下の出力が得られ、C:\xxx\batch\target
配下にoutput.csv
が作成されていれば、プロジェクトは正しく作成できている。
C:\xxx\batch>mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Macchinetta Batch Framework (2.x) Blank Project 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(.. omitted)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 56.497 s
[INFO] Finished at: 2019-09-03T10:39:59+09:00
[INFO] Final Memory: 25M/145M
[INFO] ------------------------------------------------------------------------
C:\xxx\batch>java -cp "lib/*;target/*" ^
More? org.springframework.batch.core.launch.support.CommandLineJobRunner ^
More? META-INF/jobs/job01.xml job01
(.. omitted)
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 10:41:24] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
$ mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Macchinetta Batch Framework (2.x) Blank Project 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(.. omitted)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:39 min
[INFO] Finished at: 2019-09-03T02:43:01+00:00
[INFO] Final Memory: 27M/189M
[INFO] ------------------------------------------------------------------------
$ java -cp 'lib/*:target/*' \
> org.springframework.batch.core.launch.support.CommandLineJobRunner \
> META-INF/jobs/job01.xml job01
(.. omitted)
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 02:43:11] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
プロジェクトの構成
前述までで作成したプロジェクトの構成について説明する。 プロジェクトは、以下の点を考慮した構成となっている。
-
起動方式に依存しないジョブの実装を実現する
-
Spring BatchやMyBatisといった各種設定の手間を省く
-
環境依存の切替を容易にする
以下に構成を示し、各要素について説明する。
(わかりやすさのため、前述のmvn archetype:generate
実行時の出力をもとに説明する。)
項番 | 説明 |
---|---|
(1) |
バッチアプリケーション全体の各種クラスを格納するrootパッケージ。 |
(2) |
バッチアプリケーション全体に関わるBean定義ファイルを格納するディレクトリ。 |
(3) |
非同期実行(DBポーリング)機能に関連する設定を記述したBean定義ファイル。 Ch04~Ch08以外(commonとか)の新規クラスについて、Copyrightとsinceの修正が完了しました。レビューをお願いします。 |
(4) |
ジョブ固有のBean定義ファイルにてimportすることで、各種設定を削減するためのBean定義ファイル。 |
(5) |
Spring Batchの挙動や、ジョブ共通の設定に対するBean定義ファイル。 |
(6) |
Spring Batchの挙動のうち、インフラストラクチャBeanに関するBean定義ファイル。 |
(7) |
ジョブ定義ファイルから参照される各種クラスを格納するパッケージ。 |
(8) |
ジョブ定義ファイルを格納するディレクトリ。 |
(9) |
バッチアプリケーション全体に関わる設定ファイルで、 |
(10) |
Logback(ログ出力)の設定ファイル。 |
(11) |
BeanValidationを用いた入力チェックにて、エラーとなった際に表示するメッセージを定義する設定ファイル。 |
(12) |
MyBatis3のMapperインタフェースの対となるMapper XMLファイル。 |
(13) |
主にログ出力時に用いるメッセージを定義するプロパティファイル。 |
また、各ファイルの関連図を以下に示す。
項番 | 説明 |
---|---|
(1) |
バッチアプリケーション全体の各種クラスを格納するrootパッケージ。 |
(2) |
バッチアプリケーション全体に関わるBean定義ファイルを格納するディレクトリ。 |
(3) |
非同期実行(DBポーリング)機能に関連する設定を記述したBean定義ファイル。 |
(4) |
ジョブ固有のBean定義ファイルにてimportすることで、各種設定を削減するためのBean定義ファイル。 |
(5) |
Spring Batchの挙動や、ジョブ共通の設定に対するBean定義ファイル。 |
(6) |
ジョブ定義ファイルから参照される各種クラスを格納するパッケージ。 |
(7) |
バッチアプリケーション全体に関わる設定ファイルで、 |
(8) |
Logback(ログ出力)の設定ファイル。 |
(9) |
BeanValidationを用いた入力チェックにて、エラーとなった際に表示するメッセージを定義する設定ファイル。 |
(10) |
MyBatis3のMapperインタフェースの対となるMapper XMLファイル。 |
(11) |
主にログ出力時に用いるメッセージを定義するプロパティファイル。 |
(12) |
ジョブ定義ファイルを格納するディレクトリ。 |
また、各ファイルの関連図を以下に示す。
開発の流れ
ジョブを開発する一連の流れについて説明する。
ここでは、詳細な説明ではなく、大まかな流れを把握することを主眼とする。
アプリケーション全体の設定
ブランクプロジェクトによってあらかじめ設定されているものは説明を割愛する。以下では、ユーザの状況に応じてカスタマイズする箇所について説明する。
これら以外の設定をカスタマイズする方法については、個々の機能にて説明する。
pom.xmlのプロジェクト情報
プロジェクトのPOMには以下の情報が仮の値で設定されているため、状況に応じて設定すること。
-
プロジェクト名(name要素)
-
プロジェクト説明(description要素)
-
プロジェクトURL(url要素)
-
プロジェクト創設年(inceptionYear要素)
-
プロジェクトライセンス(licenses要素)
-
プロジェクト組織(organization要素)
データベース関連の設定
データベース関連の設定は複数箇所にあるため、それぞれを修正すること。
<!-- (1) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
# (2)
# Admin DataSource settings.
admin.jdbc.driver=org.h2.Driver
admin.jdbc.url=jdbc:h2:mem:batch-admin;DB_CLOSE_DELAY=-1
admin.jdbc.username=sa
admin.jdbc.password=
# (2)
# Job DataSource settings.
#jdbc.driver=org.postgresql.Driver
#jdbc.url=jdbc:postgresql://localhost:5432/postgres
#jdbc.username=postgres
#jdbc.password=postgres
jdbc.driver=org.h2.Driver
jdbc.url=jdbc:h2:mem:batch;DB_CLOSE_DELAY=-1
jdbc.username=sa
jdbc.password=
# (3)
# Spring Batch schema initialize.
data-source.initialize.enabled=true
spring-batch.schema.script=classpath:org/springframework/batch/core/schema-h2.sql
terasoluna-batch.commit.script=classpath:org/terasoluna/batch/async/db/schema-commit.sql
// (3)
@Bean
public DataSourceInitializer dataSourceInitializer(@Qualifier("adminDataSource") DataSource adminDataSource,
@Value("${data-source.initialize.enabled:false}") boolean enabled,
@Value("${spring-batch.schema.script}") Resource script,
@Value("${terasoluna-batch.commit.script}") Resource commitScript) {
final DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(adminDataSource);
dataSourceInitializer.setEnabled(enabled);
ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator(script, commitScript);
resourceDatabasePopulator.setContinueOnError(true);
dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);
return dataSourceInitializer;
}
// (4)
@Bean(destroyMethod = "close")
public BasicDataSource adminDataSource(@Value("${admin.jdbc.driver}") String driverClassName,
@Value("${admin.jdbc.url}") String url,
@Value("${admin.jdbc.username}") String username,
@Value("${admin.jdbc.password}") String password) {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaxTotal(10);
dataSource.setMinIdle(1);
dataSource.setMaxWaitMillis(5000);
dataSource.setDefaultAutoCommit(false);
return dataSource;
}
// (4)
@Bean(destroyMethod = "close")
public BasicDataSource jobDataSource(@Value("${jdbc.driver}") String driverClassName,
@Value("${jdbc.url}") String url,
@Value("${jdbc.username}") String username,
@Value("${jdbc.password}") String password) {
final BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName(driverClassName);
basicDataSource.setUrl(url);
basicDataSource.setUsername(username);
basicDataSource.setPassword(password);
basicDataSource.setMaxTotal(10);
basicDataSource.setMinIdle(1);
basicDataSource.setMaxWaitMillis(5000);
basicDataSource.setDefaultAutoCommit(false);
return basicDataSource;
}
// (5)
@Bean
public SqlSessionFactory jobSqlSessionFactory(@Qualifier("jobDataSource") DataSource jobDataSource) throws Exception {
final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(jobDataSource);
final org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
configuration.setLazyLoadingEnabled(true);
configuration.setAggressiveLazyLoading(false);
configuration.setDefaultFetchSize(1000);
configuration.setDefaultExecutorType(ExecutorType.REUSE);
sqlSessionFactoryBean.setConfiguration(configuration);
return sqlSessionFactoryBean.getObject();
}
<!-- (3) -->
<jdbc:initialize-database data-source="adminDataSource"
enabled="${data-source.initialize.enabled:false}"
ignore-failures="ALL">
<jdbc:script location="${spring-batch.schema.script}" />
<jdbc:script location="${terasoluna-batch.commit.script}" />
</jdbc:initialize-database>
<!-- (4) -->
<bean id="adminDataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close"
p:driverClassName="${admin.jdbc.driver}"
p:url="${admin.jdbc.url}"
p:username="${admin.jdbc.username}"
p:password="${admin.jdbc.password}"
p:maxTotal="10"
p:minIdle="1"
p:maxWaitMillis="5000"
p:defaultAutoCommit="false"/>
<!-- (4) -->
<bean id="jobDataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driver}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
p:maxTotal="10"
p:minIdle="1"
p:maxWaitMillis="5000"
p:defaultAutoCommit="false" />
<!-- (5) -->
<bean id="jobSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="jobDataSource" >
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration"
p:localCacheScope="STATEMENT"
p:lazyLoadingEnabled="true"
p:aggressiveLazyLoading="false"
p:defaultFetchSize="1000"
p:defaultExecutorType="REUSE" />
</property>
</bean>
// (5)
@Bean
public SqlSessionFactory adminSqlSessionFactory(@Qualifier("adminDataSource") DataSource adminDataSource,
DatabaseIdProvider databaseIdProvider) throws Exception {
final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(adminDataSource);
sqlSessionFactoryBean.setDatabaseIdProvider(databaseIdProvider);
final org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
configuration.setLazyLoadingEnabled(true);
configuration.setAggressiveLazyLoading(false);
configuration.setDefaultFetchSize(1000);
configuration.setDefaultExecutorType(ExecutorType.REUSE);
sqlSessionFactoryBean.setConfiguration(configuration);
return sqlSessionFactoryBean.getObject();
}
<!-- (5) -->
<bean id="adminSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="adminDataSource" >
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration"
p:localCacheScope="STATEMENT"
p:lazyLoadingEnabled="true"
p:aggressiveLazyLoading="false"
p:defaultFetchSize="1000"
p:defaultExecutorType="REUSE" />
</property>
</bean>
項番 | 説明 |
---|---|
(1) |
pom.xmlでは利用するデータベースへの接続に使用するJDBCドライバの依存関係を定義する。 |
(2) |
JDBCドライバの接続設定をする。 |
(3) |
Spring BatchやMacchinetta Batch 2.xが利用するデータベースの初期化処理を実行するか否か、および、利用するスクリプトを定義する。 |
(4) |
データソースの設定をする。 |
(5) |
MyBatisの挙動を設定する。 |
ジョブの作成
ジョブは、ジョブのBean定義ファイルと、そこから参照されるコンポーネントで構成される。
基本的な実装方針を下表にまとめた。
JavaConfig | XMLConfig | |
---|---|---|
ジョブのBean定義 |
|
|
ステップのBean定義 |
|
|
タスクレットの定義 |
|
|
ItemReader/ItemWriter |
|
|
ItemProcessor |
|
|
Bean名(BeanID)の決定 |
|
|
Beanのインジェクション方法 |
メソッドインジェクションを使用する |
|
ネームスペースについては、以下の公式ドキュメントを参照のこと。
JavaConfigでのBeanのインジェクション時の注意事項
|
より詳細な作成方法の説明は、以下を参照。
プロジェクトのビルドと実行
プロジェクトのビルドと実行について説明する。
アプリケーションのビルド
プロジェクトのルートディレクトリに移動し、以下のコマンドを発行する。
$ mvn clean dependency:copy-dependencies -DoutputDirectory=lib package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Macchinetta Batch Framework (2.x) Blank Project 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(.. omitted)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:39 min
[INFO] Finished at: 2019-09-03T02:43:01+00:00
[INFO] Final Memory: 27M/189M
[INFO] ------------------------------------------------------------------------
これにより、以下が生成される。
-
<ルートディレクトリ>/target/[artifactId]-[version].jar
-
作成したバッチアプリケーションのJarが生成される
-
-
<ルートディレクトリ>/lib/(依存Jarファイル)
-
依存するJarファイル一式がコピーされる
-
試験環境や商用環境へ配備する際は、これらのJarファイルを任意のディレクトリにコピーすればよい。
環境に応じた設定ファイルの切替
プロジェクトのpom.xmlでは、初期値として以下のProfileを設定している。
<profiles>
<!-- Including application properties and log settings into package. (default) -->
<profile>
<id>IncludeSettings</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<exclude-property/>
<exclude-log/>
</properties>
</profile>
<!-- Excluding application properties and log settings into package. -->
<profile>
<id>ExcludeSettings</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<exclude-property>batch-application.properties</exclude-property>
<exclude-log>logback.xml</exclude-log>
</properties>
</profile>
</profiles>
ここでは、環境依存となる設定ファイルを含めるかどうか
を切替ている。
この設定を活用して、環境配備の際に設定ファイルを別途配置することで環境差分を吸収することができる。
また、これを応用して、試験環境と商用環境でJarに含める設定ファイルを変えることもできる。
以下に、一例を示す。
<dependencies>
<!-- omitted -->
<dependency>
<groupId>${jdbc.driver.groupId}</groupId>
<artifactId>${jdbc.driver.artifactId}</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<!-- omitted -->
<profiles>
<!-- omitted -->
<profile>
<id>postgresql12-local</id>
<properties>
<jdbc.driver.groupId>org.postgresql</jdbc.driver.groupId>
<jdbc.driver.artifactId>postgresql</jdbc.driver.artifactId>
<!-- omitted -->
</properties>
</profile>
<!-- omitted -->
<profile>
<id>oracle19c-local</id>
<properties>
<jdbc.driver.groupId>com.oracle.database.jdbc</jdbc.driver.groupId>
<jdbc.driver.artifactId>ojdbc8</jdbc.driver.artifactId>
<!-- omitted -->
</properties>
</profile>
</profiles>
なお、MavenのProfileは以下の要領で、コマンド実行時に有効化することができる。
必要に応じて、複数Profileを有効化することもできる。必要に応じて、有効活用してほしい。
$ mvn -P profile-1,profile-2
LocalVariableTableParameterNameDiscovererの廃止について
アプリケーションで
pom.xmlの記述例
|
アプリケーションの実行
前段でビルドした結果をもとに、ジョブを実行する例を示す。
[artifactId]
と[version]
はプロジェクトの作成にて設定したものに、ユーザに応じて読み替えてほしい。
C:\xxx>java -cp "target\[artifactId]-[version].jar;lib\*" ^
org.springframework.batch.core.launch.support.CommandLineJobRunner ^
com.example.batch.jobs.Job01Config job01
(.. omitted)
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 10:41:24] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
$ java -cp 'target/[artifactId]-[version].jar:lib/*' \
org.springframework.batch.core.launch.support.CommandLineJobRunner \
com.example.batch.jobs.Job01Config job01
(.. omitted)
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 02:43:11] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
C:\xxx>java -cp "target\[artifactId]-[version].jar;lib\*" ^
org.springframework.batch.core.launch.support.CommandLineJobRunner ^
META-INF/jobs/job01.xml job01
(.. omitted)
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 10:41:24] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 10:41:24] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
$ java -cp 'target/[artifactId]-[version].jar:lib/*' \
org.springframework.batch.core.launch.support.CommandLineJobRunner \
META-INF/jobs/job01.xml job01
(.. omitted)
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] launched with the following parameters: [{jsr_batch_run_id=1}]
[2019/09/03 02:43:11] [main] [o.s.b.c.j.SimpleStepHandler] [INFO ] Executing step: [job01.step01]
[2019/09/03 02:43:11] [main] [o.s.b.c.l.s.TaskExecutorJobLauncher] [INFO ] Job: [FlowJob: [name=job01]] completed with the following parameters: [{jsr_batch_run_id=1}] and the following status: [COMPLETED]
これにより、<ルートディレクトリ>/target/output.csvが生成される。
javaコマンドが返却する終了コードをハンドリングする必要性
実際のシステムでは、
ジョブスケジューラからジョブを発行する際にjavaコマンドを直接発行するのではなく、
java起動用のシェルスクリプトを挟んで起動することが一般的である。 これはjavaコマンド起動前の環境変数を設定するためや、javaコマンドの終了コードをハンドリングするためである。
この、
以下に、終了コードのハンドリング例を示す。 終了コードのハンドリング例
|
Appendix
DefaultBatchConfiguration
org.springframework.batch.core.configuration.support.DefaultBatchConfiguration
は、Spring Batchにより、JavaConfig向けにのみ提供されるConfigurationクラスである。
詳しくは、Spring Batchの公式リファレンス(以下)を参照のこと。
DefaultBatchConfiguration
は、Spring Batchの動作に必要ないくつかのBean定義(以下)を、あらかじめ設定済みにして提供する。
-
JobRepository
-
JobExplorer
-
JobLauncher
-
JobRegistry
-
JobOperator
DefaultBatchConfiguration
に相当する仕組みは、XMLConfig向けには提供されない。そのためXMLConfigでは、上述の5つのBean定義は、launch-context.xml
に記述している。
TerasolunaBatchConfiguration
TerasolunaBatchConfiguration
は、DefaultBatchConfiguration
のBean定義をカスタマイズするために用意されている。Bean定義のカスタマイズは、DefaultBatchConfiguration
のBeanメソッドをオーバーライドすることで実現する。
TerasolunaBatchConfiguration
でカスタマイズするBeanと、カスタマイズ内容は以下となる。
-
JobRepository
-
トランザクション分離レベルを
SERIALIZABLE
からREAD COMMITTED
に変更
-
-
JobOperator
-
JobParametersConverter
の実装クラスを、org.springframework.batch.core.converter.DefaultJobParametersConverter
からorg.terasoluna.batch.converter.JobParametersConverterImpl
に変更
-
以下は、JobRepository
とJobOperator
のカスタマイズ箇所のコードとなる。
// omitted.
@Override
@Bean
public JobRepository jobRepository() throws BatchConfigurationException {
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
jobRepositoryFactoryBean.setDataSource(
getDataSource());
jobRepositoryFactoryBean.setTransactionManager(
getTransactionManager());
jobRepositoryFactoryBean.setIncrementerFactory(getIncrementerFactory());
jobRepositoryFactoryBean.setClobType(getClobType());
jobRepositoryFactoryBean.setTablePrefix(getTablePrefix());
jobRepositoryFactoryBean.setSerializer(getExecutionContextSerializer());
jobRepositoryFactoryBean.setConversionService(getConversionService());
jobRepositoryFactoryBean.setJdbcOperations(getJdbcOperations());
jobRepositoryFactoryBean.setLobHandler(getLobHandler());
jobRepositoryFactoryBean.setCharset(getCharset());
jobRepositoryFactoryBean.setMaxVarCharLength(getMaxVarCharLength());
jobRepositoryFactoryBean.setIsolationLevelForCreateEnum(
Isolation.READ_COMMITTED); // (1)
jobRepositoryFactoryBean.setValidateTransactionState(
getValidateTransactionState());
try {
jobRepositoryFactoryBean.setDatabaseType(getDatabaseType());
jobRepositoryFactoryBean.afterPropertiesSet();
return jobRepositoryFactoryBean.getObject();
} catch (BatchConfigurationException e) {
throw e;
} catch (Exception e) {
throw new BatchConfigurationException(
"Unable to configure the customized job repository", e);
}
}
// omitted.
@Override
@Bean
public JobOperator jobOperator() throws BatchConfigurationException {
JobOperatorFactoryBean jobOperatorFactoryBean = new JobOperatorFactoryBean();
jobOperatorFactoryBean.setTransactionManager(
getTransactionManager());
jobOperatorFactoryBean.setJobRepository(jobRepository());
jobOperatorFactoryBean.setJobExplorer(jobExplorer());
jobOperatorFactoryBean.setJobRegistry(jobRegistry());
jobOperatorFactoryBean.setJobLauncher(jobLauncher());
JobParametersConverterImpl jobParametersConverter = new JobParametersConverterImpl(
getDataSource()); // (2)
jobOperatorFactoryBean.setJobParametersConverter(
jobParametersConverter);
try {
jobParametersConverter.afterPropertiesSet();
jobOperatorFactoryBean.afterPropertiesSet();
return jobOperatorFactoryBean.getObject();
} catch (BatchConfigurationException e) {
throw e;
} catch (Exception e) {
throw new BatchConfigurationException(
"Unable to configure the customized job operator", e);
}
}
// omitted.
項番 | 説明 |
---|---|
(1) |
トランザクション分離レベルを |
(2) |
|