TaskletStep
區塊導向處理 不是在 Step
中處理的唯一方式。如果 Step
必須包含預存程序呼叫呢?您可以將呼叫實作為 ItemReader
,並在程序完成後傳回 null。但是,這樣做有點不自然,因為會需要一個 no-op ItemWriter
。Spring Batch 為此情境提供了 TaskletStep
。
Tasklet
介面有一個方法 execute
,TaskletStep
會重複呼叫此方法,直到它傳回 RepeatStatus.FINISHED
或拋出例外以表示失敗。每次對 Tasklet
的呼叫都包裝在交易中。Tasklet
實作者可能會呼叫預存程序、腳本或 SQL 更新語句。
-
Java
-
XML
若要在 Java 中建立 TaskletStep
,傳遞給建構器的 tasklet
方法的 bean 應實作 Tasklet
介面。建構 TaskletStep
時,不應呼叫 chunk
。以下範例顯示一個簡單的 tasklet
@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/>
元素。以下範例顯示一個簡單的 tasklet
<step id="step1">
<tasklet ref="myTasklet"/>
</step>
如果實作了 StepListener 介面,TaskletStep 會自動將 tasklet 註冊為 StepListener 。 |
TaskletAdapter
與 ItemReader
和 ItemWriter
介面的其他适配器一樣,Tasklet
介面包含一個實作,允許將自身适配到任何預先存在的類別:TaskletAdapter
。一個可能有用範例是現有的 DAO,用於更新一組記錄上的旗標。您可以使用 TaskletAdapter
呼叫此類別,而無需為 Tasklet
介面編寫适配器。
-
Java
-
XML
以下範例顯示如何在 Java 中定義 TaskletAdapter
@Bean
public MethodInvokingTaskletAdapter myTasklet() {
MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter();
adapter.setTargetObject(fooDao());
adapter.setTargetMethod("updateFoo");
return adapter;
}
以下範例顯示如何在 XML 中定義 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>
Tasklet
實作範例
許多批次處理 Job 包含必須在主要處理開始之前完成的步驟,以設定各種資源,或在處理完成後清理這些資源。對於大量處理檔案的 Job 而言,通常需要在成功上傳到另一個位置後,從本機刪除某些檔案。以下範例(取自 Spring Batch 範例專案)是一個具有此類責任的 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
方法僅被呼叫一次。剩下的就是從 step
參考 tasklet
。
-
Java
-
XML
以下範例顯示如何在 Java 中從 step
參考 tasklet
@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;
}
以下範例顯示如何在 XML 中從 step
參考 tasklet
<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>