TaskletStep
Chunk-oriented processing并不是在 Step`中处理的唯一方法。如果`Step`必须包含存储过程调用会怎样?你可以将调用实现为 `ItemReader
,并在过程完成后返回 null。但是,这样做有点不自然,因为需要存在一个 no-op ItemWriter
。Spring Batch 为此场景提供了 TaskletStep
。
Chunk-oriented processing is not the only way to process in a
Step
. What if a Step
must consist of a stored procedure call? You could
implement the call as an ItemReader
and return null after the procedure finishes.
However, doing so is a bit unnatural, since there would need to be a no-op ItemWriter
.
Spring Batch provides the TaskletStep
for this scenario.
Tasklet
接口有一个方法 execute
,在 TaskletStep
调用此方法,直到它返回 RepeatStatus.FINISHED
或抛出异常以表示失败。对 Tasklet
的每个调用都被包装在一个事务中。Tasklet
实现者可以调用存储过程、脚本或 SQL 更新语句。
The Tasklet
interface has one method, execute
, which is called
repeatedly by the TaskletStep
until it either returns RepeatStatus.FINISHED
or throws
an exception to signal a failure. Each call to a Tasklet
is wrapped in a transaction.
Tasklet
implementors might call a stored procedure, a script, or a SQL update
statement.
- Java
-
要在 Java 中创建
TaskletStep
,传递给构建器tasklet
方法的 bean 应该实现Tasklet
接口。构建TaskletStep
时不应该调用chunk
。以下示例显示了一个简单的任务项:
To create a TaskletStep
in Java, the bean passed to the tasklet
method of the builder
should implement the Tasklet
interface. No call to chunk
should be called when
building a TaskletStep
. The following example shows a simple tasklet:
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet(myTasklet(), transactionManager)
.build();
}
- XML
-
要在 XML 中创建
TaskletStep
,<tasklet/>
元素的ref
属性应该引用定义Tasklet
对象的 bean。在<tasklet/>
内不应该使用<chunk/>
元素。以下示例显示了一个简单的任务项:
To create a TaskletStep
in XML, the ref
attribute of the <tasklet/>
element should
reference a bean that defines a Tasklet
object. No <chunk/>
element should be used
within the <tasklet/>
. The following example shows a simple tasklet:
<step id="step1">
<tasklet ref="myTasklet"/>
</step>
如果它实现了 |
If it implements the |
TaskletAdapter
与其他 ItemReader
和 ItemWriter
接口适配器一样,Tasklet
接口包含一个允许适配自身到任何预先存在的类的实现:TaskletAdapter
。一个可能用得上的例子是一个用于更新一组记录的标志的现有 DAO。您可以使用 TaskletAdapter
调用这个类,而不必为 Tasklet
接口编写一个适配器。
As with other adapters for the ItemReader
and ItemWriter
interfaces, the Tasklet
interface contains an implementation that allows for adapting itself to any pre-existing
class: TaskletAdapter
. An example where this may be useful is an existing DAO that is
used to update a flag on a set of records. You can use the TaskletAdapter
to call this
class without having to write an adapter for the Tasklet
interface.
- Java
-
以下示例显示如何在 Java 中定义
TaskletAdapter
:
The following example shows how to define a TaskletAdapter
in Java:
@Bean
public MethodInvokingTaskletAdapter myTasklet() {
MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter();
adapter.setTargetObject(fooDao());
adapter.setTargetMethod("updateFoo");
return adapter;
}
- XML
-
以下示例显示如何在 XML 中定义
TaskletAdapter
:
The following example shows how to define a TaskletAdapter
in 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>
Example Tasklet
Implementation
很多批作业包含必须在主处理开始前(用以设置各种资源)或处理完成后(用以清理这些资源)执行的步骤。在大量使用文件的作业的情况下,通常有必要在已成功上传文件到另一个位置后删除某些本地文件。以下示例(取自 link:https://github.com/spring-projects/spring-batch/tree/main/spring-batch-samples[SpringBatch 样例项目)是一个具有这样职责的 Tasklet
实现:
Many batch jobs contain steps that must be done before the main processing begins,
to set up various resources or after processing has completed to cleanup those
resources. In the case of a job that works heavily with files, it is often necessary to
delete certain files locally after they have been uploaded successfully to another
location. The following example (taken from the
Spring
Batch samples project) is a Tasklet
implementation with just such a responsibility:
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.state(directory != null, "directory must be set");
}
}
前一个 tasklet
实现删除了给定目录中的所有文件。需要注意的是,只调用一次 execute
方法。剩下的就是从 step
引用 tasklet
。
The preceding tasklet
implementation deletes all files within a given directory. It
should be noted that the execute
method is called only once. All that is left is to
reference the tasklet
from the step
.
- Java
-
以下示例显示如何在 Java 中从
step
引用tasklet
:
The following example shows how to reference the tasklet
from the step
in 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;
}
- XML
-
以下示例显示如何在 XML 中从
step
引用tasklet
:
The following example shows how to reference the tasklet
from the step
in 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>