M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

Spring Batchでリーダーもライターもいらない処理をステップにする

引き続きSpring Batchの公式リファレンスからの抜粋です。今回は「タスクレット」についての記述。原典は"Spring Batch - Reference Documentation"の第5章2節「タスクレット・ステップ」(バージョンは3.0.2.RELEASE。2014/12/31取得)です。

          *  *  *

5.2 タスクレット・ステップ

チャンク指向の処理がStepにおける唯一の処理方法であるというわけではありません。Stepがストアドプロシージャの呼び出しのみからなる場合はどうなるのでしょう? こうした場合でも ItemReader を呼び出し、その内部でストアドプロシージャの呼び出しを行わせた上でnullを返させてステップを終える、という実装方式をとることも可能ではあります。しかし実際には何もしない ItemWriter が必要になるわけですから、ちょっと不自然なものになります。Spring BatchはこのようなシナリオのためにTaskletStepを提供しています。

Taskletexecuteという単一のメソッドしか持たないシンプルなインターフェースです。このメソッド RepeatStatus.FINISHED を戻り値として返すか処理が失敗したことを示す例外をスローするかしない限り、TaskletStepにより繰り返し呼び出されます。各Tasklet の呼び出しは個別のトランザクションの中で行われます。Tasklet実装はストアドプロシージャを呼び出すことも、スクリプトを実行することも、はたまた簡単なUPDATEステートメントを実行することも可能です。TaskletStepを生成するには<tasklet/>要素のref属性にTasklet オブジェクトのビーン定義を参照を指定する必要があります。<tasklet/>の子要素として<chunk/>要素を使用してはいけません:

<step id="step1">
    <tasklet ref="myTasklet"/>
</step>

NOTE: タスクレットが StepListener インターフェースを実装している場合、 TaskletStep は当該タスクレットを StepListener として自動的に登録します。

5.2.1 タスクレット・アダプター

ItemReaderインターフェースやItemWriterインターフェースのために用意されたアダプターと同様に、 Tasklet インターフェースにもインターフェースと既存のクラスを橋渡しするための実装──TaskletAdapterが用意されています。例えばレコード・セットのフラグを更新するのに便利な既存のDAOを再利用したいとします。TaskletAdapterを使用すれば、この既存クラスのメソッドを呼び出すのに、アダプター・クラスを実装せずに済みます:

<bean id="myTasklet" class="o.s.b.core.step.tasklet.MethodInvokingTaskletAdapter">
    <property name="targetObject">
        <bean class="org.mycompany.FooDao"/>
    </property>
    <property name="targetMethod" value="updateFoo" />
</bean>

5.2.2 タスクレット実装例

多くのバッチ・ジョブは次のような処理を含んでいます。つまり、各種のリソースを準備するために主処理が開始されるまえに実行されなくてはならない処理や、それらのリソースをクリーンナップするために主処理が終わったあとに実行されなくてはならない処理です。大量のファイルを読み書きするジョブの場合、それらのファイルのデータを別の場所に転送したあとに、手元のファイルを削除しなくてはならないということがしばしば発生します。以下の Tasklet 実装例はまさにこのような状況のために用意されたもので、Spring Batchのサンプル・プロジェクトからの引用です:

public class FileDeletingTasklet implements Tasklet, InitializingBean {

    private Resource directory;

    public RepeatStatus execute(StepContribution contribution,
                                ChunkContext chunkContext) throws Exception {
        File dir = directory.getFile();
        Assert.state(dir.isDirectory());

        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            boolean deleted = files[i].delete();
            if (!deleted) {
                throw new UnexpectedJobExecutionException("Could not delete file " +
                                                          files[i].getPath());
            }
        }
        return RepeatStatus.FINISHED;
    }

    public void setDirectoryResource(Resource directory) {
        this.directory = directory;
    }

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(directory, "directory must be set");
    }
}

上記のTasklet 実装は指定されたディレクトリ直下のファイルをすべて削除します。executeメソッドは1回しか呼び出されない点に注意してください。あとはStepTaskletへの参照を設定するだけです:

<job id="taskletJob">
    <step id="deleteFilesInDir">
       <tasklet ref="fileDeletingTasklet"/>
    </step>
</job>

<beans:bean id="fileDeletingTasklet"
            class="org.springframework.batch.sample.tasklet.FileDeletingTasklet">
    <beans:property name="directoryResource">
        <beans:bean id="directory"
                    class="org.springframework.core.io.FileSystemResource">
            <beans:constructor-arg value="target/test-outputs/test-dir" />
        </beans:bean>
    </beans:property>
</beans:bean>

          *  *  *

原典は"Spring Batch - Reference Documentation"の第5章2節「タスクレット・ステップ」(バージョンは3.0.2.RELEASE。2014/12/31取得)です。


Spring関連の訳出記事まとめ - M12i.