Spring Batchの用語とステレオタイプ
今度は公式リファレンスから、Spring Batchフレームワークの用語と「ステレオタイプ」について。
ここで「ステレオタイプ」とは「フレームワークを利用するにあたって必要になるオブジェクト・グラフの構成要素」とか「フレームワークの中である限定された役割を負わされたオブジェクト」とかそのような意味です。Spring Web MVCなどでは@Service
アノテーションなどに関してこの用語が登場したような気がします。いずれにせよ社会科学あがりの人間にはちょっと戸惑いがあります。
今回はこうしたわりと概念的なことをとにかく押さえておきたいというのが目的ですので、リファレンスも斜め読み的に訳出しました。原典は"Spring Batch - Reference Documentation"(3.0.2.RELEASE。2014/12/29取得)の第3章「バッチのドメイン言語」です。原典には図表などもあります。そちらも見ておいたほうがわかりやすいかもしれません。
* * *
3.1 ジョブ
このセクションではバッチ・ジョブの概念に関わるステレオタイプについて説明します。 Job
は独立したバッチ処理を包み込むものです。他のSpringプロジェクトのオブジェクトと同様に、Job
はXMLコンフィギュレーションもしくはJavaコード・ベースのコンフィギュレーションにより組み立てられることになります。この過程は「ジョブ・コンフィギュレーション」と呼ばれます。Job
は〔Spring Batchを構成する〕階層構造全体のなかの最上部に位置づけられます。
〔・・・中略・・・〕
Spring Batchでは、ジョブはステップのコンテナに外なりません。ジョブにより複数のステップが1つの流れのなかで論理的に組み合わされ、再実行できるかどうかというような、すべてのステップに共通のプロパティの設定が可能になります。ジョブ・コンフィギュレーションには次のものが含まれます:
- ジョブの単純名
- ステップの内容定義とその実行順序の定義
- ジョブが再実行できるかどうかの指定
Job
インターフェースのデフォルトの簡素な実装がSpring Batchにより提供されています。SimpleJob
クラスはJob
インターフェースの上にいくつかの標準的な機能を盛り込んでいます。しかし〔XMLコンフィギュレーションの〕バッチ名前空間を用いることで、このクラスを直接に初期化せずに済みます〔つまりSimpleJob
というクラス名は忘れてよいということです〕。<job>は次のように使うことができます:
<job id="footballJob"> <step id="playerload" next="gameLoad"/> <step id="gameLoad" next="playerSummarization"/> <step id="playerSummarization"/> </job>
3.1.1 ジョブ・インスタンス
JobInstance
は論理的なジョブ実行の概念を指し示すものです。先ほどの図〔訳注:こちらが原典の図です。〕の「EndOfDay」ジョブのように、一日の終りに1回だけ実行されるバッチ・ジョブについて考えてみましょう。「EndOfDay」という名前のJob
が1つあります。しかしこのJob
の各回の実行は、個別に記録されなくてはなりません。このジョブのケースでは、論理的な JobInstance
は1日あたり1つ存在することになります。例えば1月1日のジョブ実行に対応するジョブ・インスタンスが1つ、続いて1月2日にも1つ・・・といった具合です。もし1月1日の実行が最初失敗し次の日に再度実行したとしたら、それは依然として1月1日の実行なのです。(ふつうこの実行にはその日に処理されるデータが対応付けられます。つまり1月1日の実行は1月1日のデータに対応したものになります。)したがって、各JobInstance
は複数の「実行」( JobExecution
についてより詳しくは後述します)を持つことができるとともに、ある一時においては単一のJobInstance
と該当のJob
の対応関係と、特定のJobParameter
のみが存在しうるということになります。
JobInstance
の定義はバッチ・ジョブにより読み込まれるであろうデータとはまったく何の関わりもありません。どのようなデータが読み込まれるかというのはもっぱら ItemReader
の実装次第ということです。例えば、「EndOfDay」の話でいえば、「有効日付」〔effective date〕とか「予定日」〔schedule date〕のようなカラムがあってそのデータが何日に属するものなのかを示すと仮定しましょう。そうすると、1月1日の実行では1日目のデータのみが読み込まれ、1月2日の実行では2日目のデータのみが読み込まれるといった具合です。これは業務的な決めの問題でしょうから、ItemReader
に一任されます。同じ JobInstance
が使われるかどうかによって、前回実行時の「状態」(すなわち ExecutionContext
ですが、これについては後述します)を使用するかどうかが決まります。新しいJobInstance
が使用される場合、「最初からはじめる」ことを意味になり、既存のインスタンス〔訳注:これは「等価と見なされるインスタンス」という意味であり、これこそが本節冒頭の「論理的な・・・」という形容の意味するところのようです〕を使う場合、一般的には「中断したところから始める」という意味になります。
3.1.2 ジョブ・パラメータ
JobInstance
の概念とそれがJob
とどう違うかについての議論をしてきました。ここで当然の疑問は次のようなものでしょう:「ある JobInstance
は他のそれとどのように区別されるのか?」これに対する答えは次のようになります:「それは JobParameters
によってである。」 JobParameters
はバッチ・ジョブを起動するにあたり使用されたパラメータのセットです。その値はジョブ・インスタンスの識別に用いることができ、実行中に参照することができます。
〔・・・中略・・・〕
前述の例では、2つのジョブ・インスタンスが登場しました。1つは1月1日、そしてもう1つが1月2日です。ジョブ自体はただ1つですが、1月1日のジョブ・パラメータで起動されたインスタンスと、1月2日のジョブ・パラメータで起動されたインスタンスとがありました。ということで、要約するとこうなります:JobInstance = Job + JobParametersによる識別。この点を理解することは、ある JobInstance
がどのように定義されるかを開発者が有効に制御することを可能にします。というのもその制御とはすなわちジョブに対してどんなパラメータを渡すかということだからです。
NOTE: すべてのジョブ・パラメータが JobInstance
の識別に関わるとは限りません。デフォルトではすべてのパラメータが識別に使用されますが、Spring Batchフレームワークは JobInstance
の識別に用いられないパラメータを伴うJob
を作ることを許しています。
3.1.3 ジョブ実行
1つのJobExecution
はJob
実行の試みの特定の1回を指す技術的な概念です。ジョブ実行は失敗に終わるかもしれませんし成功に終わるかもしれません。その実行に対応する JobInstance
は実行結果について関知しません。前述のEndOfDay Job
の例を使って説明すると、1月1日分の JobInstance
は最初失敗という結果となりました。ここで、最初と同じパラメータ(1月1日)を与えて同じジョブを実行すると、新しい JobExecution
が生成されます。しかしJobInstance
は1つのままです。
Job
はバッチ・ジョブの処理内容とそれがどのように実行されるかを定義するものです。そして JobInstance
は主に意味論上等価な再実行を適切に行えるようにするため複数のジョブ実行をまとめる、純粋に構成された概念です。これに対して JobExecution
は、ジョブの実行中に起こった出来事や制御され永続化されなくてはならない各種のプロパティを記録するための機能です。
Table 3.1. ジョブ実行のプロパティ
status | BatchStatus 型。このオブジェクトは、当該のジョブ実行のスタータスを表します。実行中はBatchStatus.STARTED、失敗するとBatchStatus.FAILED、そして成功裡に済めばBatchStatus.COMPLETEDです。 |
|
startTime | java.util.Date 型。この値はジョブ実行が開始されたときの当該システム時間を表します。 |
|
endTime | java.util.Date 型。この値はジョブ実行が終了したときの当該システム時間を表します。実行結果については関知しません。 |
|
exitStatus | ExitStatus 型。実行結果を表します。これはもっとも重要な項目です。終了コードは呼び出し元に返されるためです。詳しくは第5章を参照してください。 |
|
createTime | java.util.Date 型。この値はジョブ実行が最初に記録されたときの当該システム時間を表します。ジョブはまだ開始されていないかもしれませんが(するとstartTimeはまだ存在しません)、createTimeは必ず存在します。この値はフレームワークがジョブ・レベルでExecutionContext を管理するのに必要とされます。 |
|
lastUpdated | java.util.Date 型。この値はジョブ実行が最後に記録されたときの当該システム時間を表します。 |
|
executionContext | この「プロパティ袋」は実行中に保存しておく必要のあるあらゆるユーザ・データ〔フレームワークに由来しない、バッチ・ジョブ固有の情報〕を保持します。 | |
failureExceptions | ジョブ実行中に遭遇した例外のリスト。ジョブ実行の失敗に際して複数の例外が発生した場合に〔それらの情報にアクセスするのに〕便利です。 |
〔・・・中略・・・〕
3.2 Stepステップ
Step
はバッチ・ジョブのなかで逐次的に実行されるべき独立した処理をカプセル化するドメイン・オブジェクトです。すべてのJob
は1つかもしくはそれ以上のステップから構成されます。Step
は実際のバッチ処理の内容を規定しそれを制御するためのすべての情報を内包しています。これはどうしても不明瞭な説明となってしまいます。というのも、結局のところStep
の内容はJob
をつくる開発者の判断で決まることだからです。ステップは開発者の好み次第で、シンプルなものにすることも、反対に複雑なものにすることもできます。シンプルなStep
であればファイルからデータをロードし、それをデータベースに登録するだけかもしれません。その場合コードはほんの少し、あるいはまったく書かずに済むかもしれません。(使用する実装次第です。)複雑なStep
であれば難しい業務ルールを持っており、それが処理の一部に適用されるかもしれません。Job
の場合と同じく、Step
もまた独自の StepExecution
を持ちます。このオブジェクトは一意の JobExecution
に対応します。
3.2.1 StepExecutionステップ実行
StepExecution
はStep
実行の試みの特定の1回を表します。 StepExecution
は JobExecution
と同様にしてStep
が実行されるたびに生成されます。ただし先行するステップが失敗したことにより当該ステップの実行が失敗した場合には StepExecution
は記録されません。StepExecution
はそのStep
が実際に起動した時にだけ生成されるのです。
ステップ実行はStepExecution
クラスのインスタンスにより表されます。それぞれのインスタンスは対応するステップとJobExecution
への参照やコミットとロールバックの回数のようなトランザクション関連データ、開始と終了の時間を保持しています。これに加えて、各ステップ実行はExecutionContext
への参照も保持します。このオブジェクトはバッチ実行のあいだ保持されている必要のある、バッチ・ジョブに固有のあらゆるデータ──例えば、各種統計情報や再実行に必要となる状態情報など──を内包しています。次に示すのはStepExecution
のプロパティの一覧です。
Table 3.8. ステップ実行のプロパティ
status | BatchStatus 型。このオブジェクトは、当該のジョブ実行のスタータスを表します。実行中はBatchStatus.STARTED、失敗するとBatchStatus.FAILED、そして成功裡に済めばBatchStatus.COMPLETEDです。 |
|
startTime | java.util.Date 型。この値はジョブ実行が開始されたときの当該システム時間を表します。 |
|
endTime | java.util.Date 型。この値はジョブ実行が終了したときの当該システム時間を表します。実行結果については関知しません。 |
|
exitStatus | ExitStatus 型。実行結果を表します。これはもっとも重要な項目です。終了コードは呼び出し元に返されるためです。詳しくは第5章を参照してください。 |
|
createTime | java.util.Date 型。この値はジョブ実行が最初に記録されたときの当該システム時間を表します。ジョブはまだ開始されていないかもしれませんが(するとstartTimeはまだ存在しません)、createTimeは必ず存在します。この値はフレームワークがジョブ・レベルでExecutionContext を管理するのに必要とされます。 |
|
lastUpdated | java.util.Date 型。この値はジョブ実行が最後に記録されたときの当該システム時間を表します。 |
|
executionContext | この「プロパティ袋」は実行中に保存しておく必要のあるあらゆるユーザ・データ〔フレームワークに由来しない、バッチ・ジョブ固有の情報〕を保持します。 | |
readCount | 成功裡に読み込むことのできた入力アイテムの数。 | |
writeCount | 成功裡に書き込むことのできた出力アイテムの数。 | |
commitCount | 当該の実行によりコミットされたトランザクションの数。 | |
rollbackCount | 当該ステップがロールバックされたことにより影響を被った業務トランザクションの回数。 | |
readSkipCount | 読み込みに失敗し、入力アイテムのスキップが発生した回数。 | |
processSkipCount | 中間処理に失敗し、処理アイテムのスキップが発生した回数。 | |
filterCount | ItemProcessor によりフィルターされたアイテムの数。 |
|
writeSkipCount | 書き込みに失敗し、出力アイテムのスキップが発生した回数。 |
3.3 実行コンテキスト
ExecutionContext
は、フレームワークにより永続化され制御されるキーと値のペアのコレクションであり、開発者に対してStepExecution
もしくはJobExecution
のスコープで状態を保存する場所を提供するものです。Quartzに親しんでいる方であれば、JobDataMap
に非常に近しいものと感じられるでしょう。もっともよく利用される例としては再実行の際の手助けです。 フラット・ファイルを入力とする例を考えてみましょう。個別の行を処理中、フレームワークはコミット・ポイントのたびに ExecutionContext
を永続化します。これによりItemReader
は実行中に致命的なエラーが発生したり、電源喪失したりしたときの状態を保存しておくことが可能になります。このために必要なことは各時点における読み込んだ行数を実行コンテキストに追加するだけです。残りの仕事〔定期的な永続化とその復元〕はフレームワークがやってくれます:
executionContext.putLong(getKey(LINES_READ_COUNT), reader.getPosition());
〔・・・中略・・・〕
3.4 JobRepository
JobRepository
はこれまで説明してきたすべてのステレオタイプの情報を永続化するメカニズムです。リポジトリはJobLauncher
、Job
、そしてStep
実装のためにCRUD操作APIを提供します。Job
が最初に起動したとき、JobExecution
がリポジトリから取得され、ジョブの実行中、一連のStepExecution
とJobExecution
はリポジトリに渡されて永続化されます:
<job-repository id="jobRepository"/>
3.5 ジョブ・ランチャー
JobLauncher
は JobParameters
のセットともにJob
を起動するためのシンプルなインターフェースです:
public interface JobLauncher { public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException; }
このインターフェースの実装は、JobRepository
から適切な JobExecution
を取得してJob
を実行することが期待されます。
3.6 アイテム・リーダー
ItemReader
はStep
のための入力データ取得を抽象化するものです。一時に1件のデータを読み込みます。ItemReader
が供給できるデータがなくなった段階で、nullを返すことでそれを表します。ItemReader
インターフェースとその種々の実装についてより詳しくは第6章「アイテム・リーダーとアイテム・ライター」を参照してください。
3.7 アイテム・ライター
ItemWriter
はStep
の出力を抽象化するものです。一時にすべてもしくはひと塊のデータを書き出します。一般に、ライターは次に受け取ることになる入力データについて何ら関知せず、メソッドが呼び出しとともに渡された入力データについてだけしか情報を持ちません。ItemWriter
インターフェースとその種々の実装についてより詳しくは第6章「アイテム・リーダーとアイテム・ライター」を参照してください。
3.8 アイテム・プロセッサー
ItemProcessor
は1件のアイテムの中間処理を抽象化するものです。ItemReader
が1件単位でデータを読み込み、ItemWriter
がそれらを複数件単位で書き出すのに対して、ItemProcessor
はデータの変換もしくはその他の業務処理を担当します。アイテムの処理中に、当該アイテムが妥当でないと判断された場合、nullを返すことでそれが書き出されるべきでないものであることを示します。ItemProcessor
インターフェースとその種々の実装についてより詳しくは第6章「アイテム・リーダーとアイテム・ライター」を参照してください。
* * *
原典は"Spring Batch - Reference Documentation"(3.0.2.RELEASE。2014/12/29取得)の第3章「バッチのドメイン言語」です。