TaskletStep

チャンク指向の処理は、Step で処理する唯一の方法ではありません。Step がストアドプロシージャコールで構成されている必要がある場合はどうなりますか ? 呼び出しを ItemReader として実装し、プロシージャの終了後に null を返すことができます。ただし、何もしない ItemWriter が必要になるため、そうするのは少し不自然です。Spring Batch は、このシナリオの TaskletStep を提供します。

Tasklet インターフェースには execute という 1 つのメソッドがあり、TaskletStep が RepeatStatus.FINISHED を返すか例外をスローして失敗を通知するまで、このメソッドが繰り返し呼び出されます。Tasklet への各呼び出しは、トランザクションにラップされます。Tasklet の実装者は、ストアドプロシージャ、スクリプト、SQL 更新ステートメントを呼び出す場合があります。

  • Java

  • XML

Java で TaskletStep を作成するには、ビルダーの tasklet メソッドに渡される Bean が Tasklet インターフェースを実装する必要があります。TaskletStep をビルドするときは、chunk の呼び出しを行わないでください。次の例は、単純なタスクレットを示しています。

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return new StepBuilder("step1", jobRepository)
    			.tasklet(myTasklet(), transactionManager)
    			.build();
}

XML で TaskletStep を作成するには、<tasklet/> 要素の ref 属性で、Tasklet オブジェクトを定義する Bean を参照する必要があります。<tasklet/> 内では <chunk/> 要素を使用しないでください。次の例は、単純なタスクレットを示しています。

<step id="step1">
    <tasklet ref="myTasklet"/>
</step>
StepListener インターフェースを実装している場合、TaskletStep は自動的にタスクレットを StepListener として登録します。

TaskletAdapter

ItemReader および ItemWriter インターフェースの他のアダプターと同様に、Tasklet インターフェースには、既存のクラス TaskletAdapter に適応できる実装が含まれています。これが役立つ例として、一連のレコードのフラグを更新するために使用される既存の DAO があります。Tasklet インターフェース用のアダプターを作成しなくても、TaskletAdapter を使用してこのクラスを呼び出すことができます。

  • Java

  • XML

次の例は、Java で TaskletAdapter を定義する方法を示しています。

Java 構成
@Bean
public MethodInvokingTaskletAdapter myTasklet() {
	MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter();

	adapter.setTargetObject(fooDao());
	adapter.setTargetMethod("updateFoo");

	return adapter;
}

次の例は、TaskletAdapter を XML で定義する方法を示しています。

XML 構成
<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>

Tasklet の実装例

多くのバッチジョブには、さまざまなリソースをセットアップするためにメイン処理を開始する前に、または処理が完了してそれらのリソースをクリーンアップするために実行する必要があるステップが含まれています。ファイルを頻繁に使用するジョブの場合、特定のファイルを別の場所に正常にアップロードした後で、ローカルで削除する必要があることがよくあります。次の例 ( Spring Batch サンプルプロジェクト [GitHub] (英語) から取得) は、まさにそのような責任を持つ Tasklet 実装です。

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(), "The resource must be a directory");

        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.state(directory != null, "Directory must be set");
    }
}

上記の tasklet 実装は、指定されたディレクトリ内のすべてのファイルを削除します。execute メソッドは 1 回だけ呼び出されることに注意してください。あとは step から tasklet を参照するだけです。

  • Java

  • XML

次の例は、Java で step から tasklet を参照する方法を示しています。

Java 構成
@Bean
public Job taskletJob(JobRepository jobRepository, Step deleteFilesInDir) {
	return new JobBuilder("taskletJob", jobRepository)
				.start(deleteFilesInDir)
				.build();
}

@Bean
public Step deleteFilesInDir(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
	return new StepBuilder("deleteFilesInDir", jobRepository)
				.tasklet(fileDeletingTasklet(), transactionManager)
				.build();
}

@Bean
public FileDeletingTasklet fileDeletingTasklet() {
	FileDeletingTasklet tasklet = new FileDeletingTasklet();

	tasklet.setDirectoryResource(new FileSystemResource("target/test-outputs/test-dir"));

	return tasklet;
}

次の例は、step から tasklet を XML で参照する方法を示しています。

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

<beans:bean id="fileDeletingTasklet"
            class="org.springframework.batch.samples.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>