Mais conteúdo relacionado
Semelhante a Jbatch実践入門 #jdt2015 (20)
Mais de Norito Agetsuma (12)
Jbatch実践入門 #jdt2015
- 2. 上妻 宜人 あげつま のりと
• Javaトラブル解析/技術サポート業務に従事
• Java EE について調べて伝えることが好き
• 日本Javaユーザグループでの講演
• JJUG CCC 2014, ナイトセミナ, JavaOne報告会 など
- 13. jBatch機能 #1 順序制御
ジョブスケジューラ
Job1 job2
Cron or EJBタイマ
0 4 * * * batch.sh
jBatch Job
Step1 Step2 Step4
Decision
(条件分岐)
Step3-1
Step3-2Split
(並行実行)
Job XML
</>
ジョブフローはXML、ステップや分岐条件はJavaで実装
Java
Java Java
Java
Java
- 16. jBatch機能#4 エラーハンドリング
• スキップ
• 例外が投げられたレコードの処理をスキップ
• 例: 入力チェックエラー行はロギングのちスキップ
• 上限を設定して、ジョブ自体の異常終了も可能
• リトライ
• 例外が投げられたら該当のステップを自動リトライ
• デフォルトはリトライなし。ジョブ異常終了。
- 21. ステップ: チャンク方式のメリット
• バッチ処理の一定の型を規定する
• 似たような処理を一つの設計にまとめる
• Reader / Writer を汎用ライブラリ化しやすい
Item
Processor
Item
Writer
Item
Reader
• CSVなどの
FlatFileReader
• XML / JSON Reader
• JDBC / JPA Reader
• ビジネスロジック
の実装
• Readerと同様に
ライブラリ提供あり
- 23. ステップ以外のジョブ構成要素 #1
• Flow: ステップをグループ化する
• Decision: 条件分岐
• Split: 並列実行。Flow毎に可能 (Step毎は不可)
ジョブ
Step1-1
Step2-1
Step1-2
Flow2
Flow3
Flow1
Decision
終了
Split
- 24. ステップ以外のジョブ構成要素 #2
• Listener: 各ジョブ要素の前後に呼ばれる
• インターセプタのようなイメージ
• 特にスキップ時のSkipListenerはよく使う (ロギング等)
ジョブ
Step1
Job Listener
Item
Processor
Item
Writer
Item
Reader
Step Listener
Skip Listener Retry Listener
- 29. ジョブ実装 #1 ジョブXMLの作成
<job id=“issueBill”>
<!-- Step1 請求額確定 -->
<step id=“importInvoice” next=“genPDFBill” >
<chunk item-count=“100”>
<reader ref=“safesFileReader”/>
<processor ref=“billProcessor”/>
<writer ref=“billWriter”/>
</chunk>
</step>
<step id=“genPDFBill”>
...
チャンク方式でファイルを読み、DBに書くステップ定義
META-INF/batch-jobs/issueBill.xml
次ステップは請求書生成
読込⇒処理 x 100回後に
出力する(デフォルト10)
ItemReader, ItemProcessor, ItemWriter定義
クラス名の頭を小文字 or FQCN で指定
- 30. ジョブ実装 #1-1 ジョブプロパティ定義
<job id=“issueBill”>
<!-- Step1 請求額確定 -->
<step id=“importInvoice” next=“genPDFBill” >
<chunk item-count=“100”>
<reader ref=“safesFileReader”>
<properties>
<property name=“fixedFileName” value=“input.csv”/>
<property name=“fileName” value=“#{jobParameters[‘fileName’]}”/>
</properties>
</reader>
<processor ref=“billProcessor”/>
<writer ref=“billWriter”/>
</chunk>
</step>
...
ItemReaderの入力ファイル名を定義する。
固定の場合と、可変の場合で定義方法は異なる。
固定的なプロパティは
値を直接ジョブXMLに定義する
可変プロパティはプロパティ名を定義
後述のジョブ起動引数で値を指定する
- 31. ジョブ実装 #1-2 スキップ定義を追加
<job id=“issueBill”>
<!-- Step1 請求額確定 -->
<step id=“importInvoice” next=“genPDFBill” >
<chunk item-count=“100” skip-limit=“10”>
<reader ref=“safesFileReader”>
<properties>
<property name=“fixedFileName” value=“input.csv”/>
<property name=“fileName” value=“#{jobParameters[‘fileName’]}”/>
</properties>
</reader>
<processor ref=“billProcessor”/>
<writer ref=“billWriter”/>
<skippable-exception-class>
<include class=“sample.InvalidRecordException”/>
</skippable-exception-class>
</chunk>
<listeners>
<listener ref=“logErrorRecordListener” />
<listeners>
</step>
...
エラー行をスキップしたい場合は、さらに設定追加
10行までスキップする
それ以上はジョブ異常終了
スキップ対象例外 (FQCN)
スキップ時リスナの定義
- 32. ジョブ実装 #2 ステップの実装
• Chunkを構成する各クラスを実装する
• スキップリスナを実装する
【Step1】
請求額確定
CSV
aa,bb
DBMS
入力 出力
請求額TBL
Bill
Processor
SalesFile
Reader
Bill
Writer
LogErrorRecordListener 【Step2】
請求書生成
【Step3】
メール送付
- 33. ジョブ実装 #2-1 ItemReaderの実装
@Named
public class SalesFileReader implements ItemReader {
public void open(Serializable checkpoint) { }
public Object readItem() throws Exception{ }
public void close() { }
public Serializable checkpointInfo() { }
}
ItemReaderには4つのAPIが定義されている
- 35. ジョブ実装 #2-1-2 ItemReader.Open
@Named
public class SalesFileReader implements ItemReader {
...
private BufferedReader reader;
private int rowNum;
public void open(Serializable checkpoint) {
reader = Files.newBufferedReader(Paths.get(fileName));
if (checkpoint != null) {
// TODO skip reader
}
}
public Serializable checkpointInfo() {
return rowNum;
}
- 36. ジョブ実装 #2-1-2 ItemReader.Open
@Named
public class SalesFileReader implements ItemReader {
...
private BufferedReader reader;
private int rowNum;
public void open(Serializable checkpoint) {
reader = Files.newBufferedReader(Paths.get(fileName));
if (checkpoint != null) {
// TODO skip reader
}
}
public Serializable checkpointInfo() {
return rowNum;
}
チェックポイント毎に呼ばれる
(item-count属性に設定した間隔)
初回スタート時はnull。
リスタート時には異常終了前最後
のcheckpointInfo()の値が渡される
- 37. ジョブ実装 #2-1-3 ItemReader.readItem
@Named
public class SalesFileReader implements ItemReader {
...
public Object readItem() {
String line = reader.readLine();
if (line == null) return null;
// TODO1 line to Sales obj
// TODO2 入力値チェック
if (!isValid()) {
throw new InvalidRecordException(rowNum, line);
}
rowNum++;
return sales;
}
入力値チェックもItemReaderの役
割。
エラー時はスキップ対象例外を返
す。
入力がなくなったらnullを返
す
- 38. ジョブ実装 #2-1-4 ItemReader.close
@Named
public class SalesFileReader implements ItemReader {
...
public void open(Serializable checkpoint) { // 済 }
public Serializable checkpointInfo() { //済 }
public Object readItem() throws Exception { // 済 }
public void close() {
reader.close();
}
...
リソースクローズ処理。
readItem()から null が返される or
異常終了時に呼ばれる。
- 40. ジョブ実装 #2-2 ItemProcessorの実装
• ItemReaderで読んだ値を引数に処理
• ビジネスロジック実装部分
【Step1】
請求額確定
CSV
aa,bb
DBMS
入力 出力
請求額TBL
Bill
Processor
SalesFile
Reader
Bill
Writer
LogErrorRecordListener 【Step2】
請求書生成
【Step3】
メール送付
済
- 41. ジョブ実装 #2-2-1 ItemProcessorの実装
@Named
public class BillProcessor implements ItemProcessor {
@Override
public Object processItem(Object item) throws Exception {
Sales sales = (Sales) item;
// ビジネスロジックをここに実装
// TODO 売上データ ⇒ 請求額 算出
return bill;
}
}
ビジネスロジックをprocessItem()に実装する
- 42. ジョブ実装 #2-3 ItemWriterの実装
• ItemProcessorで処理した値を引数に
• データを書き出す部分
【Step1】
請求額確定
CSV
aa,bb
DBMS
入力 出力
請求額TBL
Bill
Processor
SalesFile
Reader
Bill
Writer
LogErrorRecordListener 【Step2】
請求書生成
【Step3】
メール送付
済 済
- 43. ジョブ実装 #2-3-1 ItemWriterの実装
@Named
public class BillWriter implements ItemWriter {
public void open(Serializable checkpoint) { }
public void writeItems(List<Object> items) throws Exception { }
public void close() { }
public Serializable checkpointInfo() { }
}
ItemReaderとの違いはwriteItemsのみ
- 44. ジョブ実装 #2-3-1 ItemWriterの実装
@Named
public class BillWriter implements ItemWriter {
@Override
public void writeItems(List<Object> items) throws Exception {
List<Bill> bills = (List<Bill>) items;
bills.stream()
.forEach(this::insertToDB);
}
private void insertToDB(Bill bill) { .. }
...
}
複数のRead => Process
結果のリストが引数に設定
コミットはwriteItemメソッドの呼び出し毎に実行
- 45. ジョブ実装 #2-4 スキップリスナ
• スキップ対象例外の発生時に呼ばれる
• エラーレコードをロギングしたい
【Step1】
請求額確定
CSV
aa,bb
DBMS
入力 出力
請求額TBL
Bill
Processor
SalesFile
Reader
BillAmount
Writer
LogErrorRecordListener 【Step2】
請求書生成
【Step3】
メール送付
済 済 済
- 46. ジョブ実装 #2-4-1 スキップリスナの実装
@Named
public class LogErrorRecordListener
implements SkipReadListener {
private static final Logger log = ...;
@Override
public void onSkipReadItem(Exception e) {
InvalidRecordException ex = (InvalidRecordException) e;
log.warn(“Row ”+ ex.getNum() + “ is Invalid Record.”);
}
} スキップした行情報のロギング。
スキップした行全体を別ファイルに書出すのもあり。
- 47. ジョブ実装 #3 ジョブの起動
• JobOperator経由で起動する
• EJBタイマ、JAX-RS/Servletなど で起動
【Step1】
請求額確定
Bill
Processor
SalesFile
Reader
BillAmount
Writer
LoggingErrorRecordListener 【Step2】
請求書生成
【Step3】
メール送付
請求書発行ジョブ
済
済済 済
JobOperator
EJBタイマ
JAX-RS/Servlet
- 48. ジョブ実装 #3-1 ジョブの起動
@ScheduleによるEJB タイマー
@javax.ejb.Singleton
public class ScheduleTimer {
@Schedule(hour=“4”, minute=“2”)
public void timeout() {
// start
JobOperator jobOperator = BatchRuntime.getJobOperator();
Property props = new Property();
props.setProperty(“fileName”, “/var/xxx/input.csv”);
jobOperator.start(“issueBill”, props);
}
} ジョブIDと、ジョブプロパティを引数に起
動
- 52. まとめ : jBatch利用の流れ
1. ジョブ設計
• ジョブを抽出。ステップと入出力を定義する。
2. ジョブ実装
• ステップの流れ、プロパティをジョブXMLに定義
• ItemReader/ItemProcessor/ItemWriterのJava実装
• JobOperator経由で起動、停止、リスタート制御
• EJBタイマ、JAX-RS Web-API 等 から起動
- 55. jBatch適用のデメリット
• 型に填めにくい処理への適用が難しい
• 複数入力(マスタ / トランザクション読込)、複数出力
• 読み込み方の工夫で解決できることもある
CSV
aa,bb
商品マスタ
【Step】
売上データ集計
ProcessorReader Writer
CSV
aa,bb
売上データ
public class Aggregate {
private Master master;
private List<Transaction> trans;
1マスタ/複数トランザクションデータ毎 に読み込み
DBMS
集計済
売り上げ
- 56. jBatch適用のデメリット
• 処理によっては記述が冗長
• XMLによる処理の流れの定義
• java.nio.file.Files.linesメソッドで十分な場合もある
// CSVファイルより、15歳以上のみ抽出して別ファイルへ
try (Stream<String> stream = Files.lines(Paths.get(“csv.txt”)) {
stream .map(line -> line.split(“,”))
.map(arr -> // TODO array to Student)
.filter(student -> student.getAge() > 15)
.forEachOrdered(s -> // write to file);
}
Reader
Processor
Writer
- 59. jBatch と SpringBatch の違い #1
• jBatchは仕様、SpringBatchは実装
• jBatch実装: RI (GlassFish), JBeret (WildFly)
• SpringBatch3.0より jBatchに準拠
• ライブラリの豊富さは先行のSpringBatch有利
SpringBatchの機能範囲
jBatch
アーキテクチャ
ジョブXML
API定義
• 豊富なライブラリ群
• CSV/TSV, XML, JDBCページング
• かゆいところに手が届く
• 同一形式の複数ファイル読込
(stock_1.csv, stock_2.csv ...)
• 複数行を1アイテムにマッピング
- 60. jBatch と SpringBatch の違い #2
• SpringBatchはジェネリクス対応
public class Reader implements ItemReader<Stock> {
@Override
public Stock read() {
// read stock
}
}
public class Processor implements ItemProcessor<Stock, Result> {
@Override
public Result process(Stock s) throws Exception { ... }
}
ジェネリクス対応により
キャストが不要
- 62. Spring Batchでは Java でジョブ定義可能
@Bean
public Job job() {
return jobsBuilderFactory.get("myJob")
.start(step1()).next(step2())
.build();
}
@Bean
protected Step step1(...) {
return stepBuilderFactory.get("step1")
.<Person, Person> chunk(10)
.reader(reader).processor(processor).writer(writer)
.build();
}
Spring Batch - Reference Documentation
http://docs.spring.io/spring-batch/trunk/reference/html/configureJob.html#javaConfig
- 72. まとめ #3
【ここが嬉しい】
• Java EE でバッチ処理が注目され始めた
• 一定の型に填めてジョブ設計を再利用できる
• ジョブに必要な共有機能が享受できる
【もう少しな部分】
• 型に填めにくい / 塡まらない場合もある
• 現状は先発のSpring Batchの方が多機能