目录
- 1、Spring Batch的四种模式
- 1.1、Multi-threaded Step
- 1.2、 Parallel Step
- 1.3、 Remote Chunking of Step
- 1.4、Partitioning Step
1、Spring Batch的四种模式
根据官网解读,Spring Batch有以下四种模式:
- Multi-threaded Step
- Parallel Step
- Remote Chunking of Step
- Partitioning Step
1.1、Multi-threaded Step
多线程Step,根据官网给出的例子,它的定义如下:
@Bean
public TaskExecutor taskExecutor(){
return new SimpleAsyncTaskExecutor("spring_batch");
}
@Bean
public Step sampleStep(TaskExecutor taskExecutor) {
return this.stepBuilderFactory.get("sampleStep")
.<String, String>chunk(5)
.reader(itemReader())
.writer(itemWriter())
.taskExecutor(taskExecutor)
.build();
}
上面这段代码配置就是用SimpleAsyncTaskExecutor线程池来进行一个多线程的读取,但是这个多线程并不是我们以前认为的一个线程处理一个setp,这里的多线程其实体现在chunk上面,就是说采用多个线程去进行数据的读取,等所有线程的reader操作完成后,然后将所有的数据封装成一个参数传给Writer,然后由writer进行提交。看下面这个模型图可能就会理解了。
注意:如果这里的线程池不是SimpleAsyncTaskExecutor,而是ThreadPoolTaskExecutor,那么此时运行的线程并不是上面代码定义的5个,而是4个。
1.2、 Parallel Step
真正的并发Step,现在来看一下关网的demo:
@Bean
public Job job() {
return jobBuilderFactory.get("job")
.start(splitFlow())
.next(step4())
.build() //builds FlowJobBuilder instance
.build(); //builds Job instance
}
@Bean
public Flow splitFlow() {
return new FlowBuilder<SimpleFlow>("splitFlow")
.split(taskExecutor())
.add(flow1(), flow2())
.build();
}
@Bean
public Flow flow1() {
return new FlowBuilder<SimpleFlow>("flow1")
.start(step1())
.next(step2())
.build();
}
@Bean
public Flow flow2() {
return new FlowBuilder<SimpleFlow>("flow2")
.start(step3())
.build();
}
@Bean
public TaskExecutor taskExecutor(){
return new SimpleAsyncTaskExecutor("spring_batch");
}
在上面这个例子中,是通过split关键字来实现并发的,但是需要注意一点的是只有Step1、Step2、Step3全部执行成功后,才会继续执行Step4。把上面的例子转化为模型图,相信大家一下就能看明白了:
1.3、 Remote Chunking of Step
官方描述如下:在远程分块中,Step处理过程分为多个进程,并通过某种中间件相互通信。下图显示了该模式:
从这张图片上来看,可以很容易的知道,该模式适合主从结构场景,整个过程大概如下:Master Step先读取数据,然后将这个数据交给某个中间件,然后Slave Step对这个中间件进行监听,当监听到有自己需要的数据的时候就从中间件拿数据,然后将数据写入到指定的地方。但是这个模型在使用的时候需要考虑负载均衡的问题。
1.4、Partitioning Step
这个模型真正意义上实现了Step的多线程,每个线程都有一个Reader、Writer,相当于每一个线程有一个Step,但是该模型真正的好处是将需要处理的数据先进行分割,然后每一个reader、writer模块对应一个数据区,这样保证了数据的同步也充分发挥了多线程的优势。先看下官网的定义:
每一个Worker相当于一个Reader和Writer,每一个worker的执行流程如下:
首先执行handler,这个hanlder的意义就是处理远程数据的划分,其实就是设置TaskExecutorPartitionHandler 参数,参数设置完成后,就调用spit函数,采用多线程的方式执行Step里面的reader和Writter操作。全部执行完成后将数据返回给下一个Step。参数配置代码如下所示:
/**
* Step配置
* @return
*/
@Bean
public Step step1Manager() {
return stepBuilderFactory.get("step1.manager")
.partitioner("step1", testPartitioner())
.partitionHandler(partitionHandler())
.build();
}
/**
* handler函数的配置
* @return
*/
@Bean
public PartitionHandler partitionHandler() {
TaskExecutorPartitionHandler retVal = new TaskExecutorPartitionHandler();
retVal.setTaskExecutor(taskExecutor());
retVal.setStep(step1());
retVal.setGridSize(10);
return retVal;
}
/**
* 设置Partitioner 数据的具体划分
*/
public class testPartitioner implements Partitioner {
@Override
public Map<String, ExecutionContext> partition(int gridSize) {
Map<String, ExecutionContext> result = new HashMap<>();
for (int i = 1; i <= gridSize; i++) {
ExecutionContext value = new ExecutionContext();
result.put("partition " + i, value);
}
return result;
}
@Bean
public TaskExecutor taskExecutor(){
return new SimpleAsyncTaskExecutor("spring_batch");
}
@Bean
public MultiResourceItemReader itemReader
(@Value("#{stepExecutionContext['fileName']}/*") Resource [] resources)
{
return new MultiResourceItemReaderBuilder<String>()
.delegate(fileReader())
.name("itemReader")
.resources(resources)
.build();
}