TaskletStep
基於 Chunk 的處理 不是 `Step` 中唯一的處理方式。如果 `Step` 必須包含儲存過程呼叫怎麼辦?您可以將該呼叫實現為 `ItemReader`,並在過程完成後返回 null。但這有點不自然,因為還需要一個無操作的 `ItemWriter`。Spring Batch 為這種情況提供了 `TaskletStep`。
`Tasklet` 介面有一個方法 `execute`,`TaskletStep` 會重複呼叫該方法,直到它返回 `RepeatStatus.FINISHED` 或丟擲異常表示失敗。每次對 `Tasklet` 的呼叫都包裹在一個事務中。`Tasklet` 實現者可以呼叫儲存過程、指令碼或 SQL update 語句。
-
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`,`
<step id="step1">
<tasklet ref="myTasklet"/>
</step>
如果 tasklet 實現了 `StepListener` 介面,`TaskletStep` 會自動將其註冊為 `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>