Springのバッチの機能の概要を見てみましょう!
一言でいえば、「バッチ処理を扱う機能」です。
【用意されている機能】
Springのバッチ処理には、主に2つの機能があります。
・スケジューリング機能
定期処理を実施する機能。裏ではquartzや、Java's Timerの機能を使用している
・バッチ処理機能
ループ処理、並列処理や、失敗時に処理を変更するなど、処理の動作を定義して実行する
Springプロジェクトの位置づけ上で、2つ共をSpringBatchというカテゴリで括るのが正しいか分かりませんが、ここの記事では括ってしまいました。大丈夫かしら
さて、スケジューリングはクーロンのように起動するだけなのでそれ程難しくありません。
実際に使用例の記事 を見てもらうほうがいいかと思います。
ですので、以下では簡単にバッチ処理機能を見ていこうと思います。
もっと詳しい内容はおいおいで記事にできればと思っています。
【バッチ処理機能】
まず、Springが提供するバッチ処理について見ていきましょう。
ちなみに現状では、バージョン1.x と 2.xが提供されています。
1.xは古い上に、作らなければいけないクラスが多いようで、あまり触れたくないので2.xを扱っていくことにします。
言葉をいくつか覚えないといけません。
そこで、一番おおまかな概要からではなく、少し細かなところから説明を開始します。
まあ、森を見る前に少し木を見ておこう的な感じかな
Springバッチでは起動を管理するための「JobInstance」という概念があり、理解しておく必要があります。
JobInstanceの簡単な説明:
JobInstanceは、起動を一意に指定する識別子のようなものです。
実際に一意のidも振られます。
例えば、毎日2回、2時と14時に起動するようにクーロンにスケジュールした場合、
起動を特定したい場合、「2010/8/17の14時のバッチ」と指定すれば1つに特定できると思います。
これをしているのがJobInstanceです。
特定さえできれば、「2010/8/17の14時のバッチ」の結果はどうなってるの?とか、
「2010/8/17の14時のバッチ」を再起動しよう!、とかをJobに命令することで可能になります。
さて、これだけだと良く分からないと思いますので、以下で具体的に見ていきましょう。
このあとの例題は、主にJobInstanceの概念を確認するためのものです。
運用でバッチを走行するとき、一般的には定期的にクーロンなどでjavaを起動します。
この例題でもクーロンで1日1度起動するように設定したとします。
バッチ処理内容は、「パラメタtargetに日付を指定するとその日のデータの処理をする」というものです。
起動イメージ:
> java CommandLineJobRunner launcher-context.xml Job1 target=2010/01/01
※実際には、CommandLineJobRunnerの部分はパッケージ名を記述する必要があります。
見づらくなるので省略しているだけです。
参考:
※上の図は、クラスをDBに保存したときの図です。
<各オブジェクトの説明>
JobParameter ・・・ 起動時のパラメタを表すクラス
Job ・・・ 起動するバッチ処理を定義したクラス
JobInstance ・・・ Job名とパラメタを保持したクラス。起動した処理を識別するための概念。
以下の起動(3)も見ないと分かりずらいと思います。
JobExecution・・・ Jobの状態、結果などを保持するクラス。JobInstanceも保持しています。
<図の説明>
2010/01/01 のデータを処理させようとしてバッチを起動。
しかし、失敗してしまった。
Jobが起動されると、JobInstanceが生成されます。
さらに、JobInstanceがJobの処理状態や結果などを保持するJobExecutionを作成します。
<2日目>
<図の説明>
今度は1日目と違う日付2010/01/02のデータを処理させようとしてバッチを起動。
うまくいった!
JobInstanceの生成は1日目と同様に行われますが、1日目とは違うJobInstanceが生成されます。
1日目とJob1を起動したことは一緒ですが、JobParameterが違うからです。
JobInstanceは、JobとJobParameterが同じときは同じ処理、と認識します。
今回は違うのでid=2という新しいidが振られました。
<3日目>
<図の説明>
1日目に失敗したことに気づき、手動で1日目と同じパラメタで再走行をし、成功した。
起動イメージは以下の感じです。
> java CommandLineJobRunner launcher-context.xml Job1 -restart
このとき、JobとJobParameterは1日目と同じになります。
ですので、id=1という1日目と同じJobInstanceが生成され、1日目と同じ処理だと認識されます。
ただし、JobExecutionは新しいものが作られます。
結果は起動ごとに当然ながら違いますので、これは分かりやすいですよね(‐^▽^‐)。
<同時起動>
さて、次にもう少しJobInstanceについて見識を深めましょう!
2つのケースを考え、Jobが実行されるかどうかを見ていきます。
(1)1日目の処理が24時間以上かかり、2日目の処理が起動されてしまった場合
⇒2日目の処理は問題なく起動されます。
(2)1日目の処理が24時間以上かかり、それに気づかずもう一度、1日目と同じ処理を起動してしまった場合
⇒JobExecutionAlreadyRunningExceptionが発生し、異常終了します。
基本的にSpringBatchでは、JobParameterが違う場合は違うデータを処理するように設計するようです。
このルールどおり実装された場合、1日目と2日目ではJobParameterが違うので
処理する対象データが違い、お互いに影響を受けない処理であることが分かると思います。
これはJobInstanceが違う場合は同時に実行しても問題ないということと同じです。
SpringBatchは、JobInstanceが違う場合(1)は2重起動OKにしているようです。
つまり、Job名が同じ処理が起動される場合でも、パラメタが違えば起動OKです。
では(2)の場合はどうでしょうか。
今度はJobInstanceが同じなので2重起動と認識して
例外JobExecutionAlreadyRunningExceptionが発生します。
なんとなくJobInstanceという概念が分かりましたでしょうか?
<全体の概要>
次に、森を見ていきましょう!
SpringBatch全体の動きです。
まず、一番偉い人は、JobLauncherというJobの実行者です。
このクラスは、JobParameterとJobを引数に受け取ってJobに実行命令を出します(①②)。
JobLauncherは実際にはinterfaceで、Springがいくつか実体クラスを用意してくれています。
ですので自分でクラスを作るケースはほとんど無いかと思います。
ちなみに実体クラスの例を書くと、SimpleJobLauncherクラスなどがあります。
次に見るのはJobとStepです。
Jobの中には複数のStepが存在し、これが実際の処理になっています。
Jobに実行命令が下ると内部のStepを設定どおりに次々に実行していきます。
JobはStep単位で処理を操作することができます。
操作例1: 普通に順番に処理する
Step1 ⇒ Step2 ⇒ Step3
操作例2: 条件分岐を入れる
Step1 ⇒(失敗時) Step2
⇒(成功時) Step3
操作例3: 並行処理
Step1 ⇒ Step2 ─⇒ Step4
⇒ Step3 ┘
※なんとなくStepのイメージ付きましたでしょうか?
最後に
JobRepositoryですが、これは結果(Execution )の保存先です。
JobLauncher、Job、Stepは、JobRepositoryを通してDBからExecutionを取得したり、保存したりできます。
例えば、Step1が終了するとその結果(StepExecution1)をDBに保存します。
Step2が終了すればその結果(StepExecution2)をDBに保存します。
こうして次々に結果が保存されます。
最後にJob全体の処理結果(JobExecution)がDBに保存されます。
すべての処理が終了し結果が保存されるとバッチ処理が終了します。
これでだいたいの概要の説明は終了です!
なんとなーく分かっていただければうれしいですが、どうでしょうか?
もう少し詳しい内容は、言葉の定義や、他の記事でサンプルを見ながら記述していこうかと思います。
つたない文章をここまで読んでいただきありがとうございました
次の記事もSpringBatchの基本概念になりますのであわせて最初に読んでいただけると嬉しいです。
【注意】
すみません。カテゴリがSpringBatchの記事はまだ実際に動作するプログラムを試していません。
SpringBatch本家のドキュメントを英訳してまとめただけなので、英訳を間違っているかもしれません。
自分の英語力は5段階で1だったので(笑)ご注意ください。すみません。m(_ _ )m
間違いあればコメントなどで教えていただければ修正します。
参照:
・データの書き込み(コミット)タイミングを制御するには? (restart機能もついでに見る!)
・ItemReaderで読み込んだデータを妥当性チェックするには? (valang方式)
FootBallを例題にサンプルを作る(英語ですがサンプルだけでも参考になります)