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>

如果它实现了 StepListener 接口,TaskletStep 会自动将 tasklet 注册为 StepListener

If it implements the StepListener interface, TaskletStep automatically registers the tasklet as a StepListener.

TaskletAdapter

与其他 ItemReaderItemWriter 接口适配器一样,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:

Java Configuration
@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:

XML Configuration
<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:

Java Configuration
@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:

XML Configuration
<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>