天天看點

Spring Batch 小任務(Tasklet)步驟

Chunk-Oriented Processing不是處理 step 的唯一方法。

考慮下面的一個場景,如果你僅僅需要調用一個存儲過程,你可以在 ItemReader 中實作這個調用,然後在存儲過程完成調用後傳回 null。這種設計看起來不是那麼自然也不是非常優美,因為你的批量設計中甚至都不需要實作 ItemWriter。針對這種情況,Spring Batch 為你提供了 TaskletStep 選項。

TaskletStep 是一個簡單的接口,這個接口隻需要實作一個方法execute,這個方法将會被TaskletStep多次重複的調用,直到這個方法傳回 RepeatStatus.FINISHED 或者抛出異常來表示調用失敗。

Tasklet 的每一次調用都會包含在事務中(Transaction)。Tasklet 的實作(implementors)可以調用一個存儲過程,一個腳本或者一個簡單的 SQL 更新腳本。

針對我們的實踐中,我們可以使用 Tasklet 來執行一個 FTP 的任務。

将我們産生的中間檔案上傳到不同的 FTP 伺服器上,你可以在實作中指定不同的伺服器配置參數,這樣更加有利于代碼的重用。

為了能夠建立一個 TaskletStep,Bean 需要傳遞一個 tasklet 方法到構造器(builder),這個 tasklet 方法需要實作 Tasklet 接口。

當你建構 TaskletStep 的時候不要調用 chunk。

下面的示例代碼顯示了一個在 Step build 中建構一個簡單的 tasklet。

@Bean

public Step step1() {

    return this.stepBuilderFactory.get("step1")

                .tasklet(myTasklet())

                .build();

}

如果你的 tasklet 實作了 StepListener  接口的話,TaskletStep 将會自動将 tasklet 注冊成為一個 StepListener。

TaskletAdapter

與 ItemReader 和 ItemWriter 接口的 adapters一樣。Tasklet  接口包含的實作也允許能夠通過已經存在的類使用 TaskletAdapter 來将自己進行注冊。

例如,你希望使用一個已經存在的 DAO 來更新記錄集上的标記的時候,你可以使用 TaskletAdapter 來進行實作。

使用 TaskletAdapter  能夠讓你的 DAO 可以被 Spring Batch 的 TaskletStep 調用而不需要讓你的 DAO 都實作 Tasklet 的接口。

如下面的示例代碼:

public MethodInvokingTaskletAdapter myTasklet() {

    MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter();

    adapter.setTargetObject(fooDao());

    adapter.setTargetMethod("updateFoo");

    return adapter;

Tasklet 實作(Implementation)示例

在主批量作業開始之前,可能需要很多其他的批量作業必須完成,這樣以便于主批量作業能夠獲得必要的資源和在完成後釋放資源或者進行清理。

例如我們遇到下面的使用場景,一個批量作業需要大量的對檔案進行互動和使用,通常來說需要在檔案被上傳到其他伺服器上後删除本地産生的臨時檔案。

下面的示例就是一個 Tasklet 的實作,這個Tasklet 的實作能夠完成上面的互動要求(檔案來自 Spring Batch samples project 示例程式)。

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  方法,這個 Tasklet 應該隻被執行一次。

所有相關執行的操作需要在 Step 中進行設定,請參考下面有關這個 Tasklet 的設定:

Java 配置

public Job taskletJob() {

    return this.jobBuilderFactory.get("taskletJob")

                .start(deleteFilesInDir())

public Step deleteFilesInDir() {

    return this.stepBuilderFactory.get("deleteFilesInDir")

                .tasklet(fileDeletingTasklet())

public FileDeletingTasklet fileDeletingTasklet() {

    FileDeletingTasklet tasklet = new FileDeletingTasklet();

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

    return tasklet;

https://www.cwiki.us/display/SpringBatchZH/TaskletStep