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;
}
|