Spring BatchのReaderである程度複雑なことをする
やりたいこと
Readerである程度複雑なことをしたい。 ある程度複雑なこととは、例えば
などです。
Readerでできること
Readerは、ItemReaderインターフェースの実装クラスです。 よく使いそうなItemReaderの実装クラスはSpring Batchで17種類提供されていますが、一回の読み込みで複数回クエリを発行するようなReaderやREST APIを叩くはものはありません。
このため、複雑なReaderは自分で実装しなくてはいけません。
ItemReader
Readerはreadメソッドが呼ばれるたびに新しいデータを一つ返します。 これは、一回のクエリ発行で一つのデータが返るような処理をすればいいということではありません。 read()はnullを返すまで実行されるので、そのようなクエリを発行したら無限ループしてしまうことになるからです。 ということは、簡単に言うと次のような実装が必要になります。
public class MyItemReader<T> implements ItemReader<T> { private List<T> data; private List <T> getData() { // なんか複雑な処理でデータをとってくる return data; } T read() { if (data == null) { data = getData(); } if (data.size() < 1) { return null; } return data.remove(0); } }
Spring Batchはリスタート機能も備えているのですが、このままでは外部からReaderを再開してあげる方法がないので、このクラスはリスタートに対応していません。
AbstractItemCountingItemStreamItemReader
リスタートできるように、どこまで読み込んだとかの管理をうまくやってくれるクラスはないのかなー。ありました。
抽象クラスAbstractItemCountingItemStreamItemReaderは、Readerが返している要素の数と返せる要素の数(最大値)を管理してくれます。 Readerで読み込んだ要素の管理は自分でしないといけませんが… JdbcPagingItemReaderなどは、この抽象クラスを継承して実装しているので、参考になるでしょう。
public class MyItemReader extends AbstractItemCountingItemStreamItemReader<T> { private List<T> data; private List <T> getData() { // なんか複雑な処理でデータをとってくる return data; } @Override protected void doOpen() throws Exception {} @Override protected Employee doRead() throws Exception { if (results == null) { data = getData(); } return results.get(getCurrentItemCount() - 1); } @Override protected void doClose() throws Exception {} }
実はこのままだと、やっぱりdataを復帰させる方法がないので、やはりリスタートには対応していません。近いうちにリスタート対応版を追記します。