Chunk-Oriented Processing不是處理 step 的惟一方法。java
考慮下面的一個場景,若是你僅僅須要調用一個存儲過程,你能夠在 ItemReader
中實現這個調用,而後在存儲過程完成調用後返回 null。這種設計看起來不是那麼天然也不是很是優美,由於你的批量設計中甚至都不須要實現 ItemWriter。針對這種狀況,Spring Batch 爲你提供了 TaskletStep 選項。git
TaskletStep
是一個簡單的接口,這個接口只須要實現一個方法execute
,這個方法將會被TaskletStep屢次重複的調用,直到這個方法返回 RepeatStatus.FINISHED
或者拋出異常來表示調用失敗。github
Tasklet
的每一次調用都會包含在事務中(Transaction)。Tasklet 的實現(implementors)能夠調用一個存儲過程,一個腳本或者一個簡單的 SQL 更新腳本。spring
針對咱們的實踐中,咱們可使用 Tasklet 來執行一個 FTP 的任務。服務器
將咱們產生的中間文件上傳到不一樣的 FTP 服務器上,你能夠在實現中指定不一樣的服務器配置參數,這樣更加有利於代碼的重用。ui
爲了可以建立一個 TaskletStep
,Bean 須要傳遞一個 tasklet 方法到構造器(builder),這個 tasklet 方法須要實現 Tasklet 接口。this
當你構建 TaskletStep 的時候不要調用 chunk
。spa
下面的示例代碼顯示了一個在 Step build 中構建一個簡單的 tasklet。.net
public
Step step1() {
return
this
.stepBuilderFactory.get(
"step1"
)
.tasklet(myTasklet())
.build();
}
|
若是你的 tasklet
實現了 StepListener
接口的話,TaskletStep
將會自動將 tasklet
註冊成爲一個 StepListener
。設計
與 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 的實現,這個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())
.build();
}
public
Step deleteFilesInDir() {
return
this
.stepBuilderFactory.get(
"deleteFilesInDir"
)
.tasklet(fileDeletingTasklet())
.build();
}
public
FileDeletingTasklet fileDeletingTasklet() {
FileDeletingTasklet tasklet =
new
FileDeletingTasklet();
tasklet.setDirectoryResource(
new
FileSystemResource(
"target/test-outputs/test-dir"
));
return
tasklet;
}
|