1. 开始执行一个Step

单线程的Step一般使用的实现类是TaskletStep Step的执行从 Step抽象类 AbstractStep中的execute方法开始
这个方法完成了一下几个工作

1.1 Step执行前的准备工作

  • 更新StepExecution 也就是Step执行信息到存储库
  • 注册StepExecution
  • 触发Step监听器的beforeStep方法
  • 执行steam接口的open方法
stepExecution.setStartTime(new Date());
	stepExecution.setStatus(BatchStatus.STARTED);
	getJobRepository().update(stepExecution);
	ExitStatus exitStatus = ExitStatus.EXECUTING;
	doExecutionRegistration(stepExecution);
	getCompositeListener().beforeStep(stepExecution);
	open(stepExecution.getExecutionContext());

1.2. 开始执行Step

  • 执行Step
  • 获取退出状态
  • 跟通信stepExecution中的状态
doExecute(stepExecution);
    exitStatus = ExitStatus.COMPLETED.and(stepExecution.getExitStatus());

	if (stepExecution.isTerminateOnly()) {
		throw new JobInterruptedException("JobExecution interrupted.");
	}

	stepExecution.upgradeStatus(BatchStatus.COMPLETED);

1.3. Step异常处理

stepExecution.upgradeStatus(determineBatchStatus(e));
	exitStatus = exitStatus.and(getDefaultExitStatusForFailure(e));
	stepExecution.addFailureException(e);

1.4. Step收尾处理

  • 计算退出状态
  • 更新StepExecutionContext到资源库
  • 更新StepExecution到资源库
  • 执行steam的close方法
  • 释放StepExecution
exitStatus = exitStatus.and(stepExecution.getExitStatus());
	stepExecution.setExitStatus(exitStatus);
	exitStatus = exitStatus.and(getCompositeListener().afterStep(stepExecution));

	try {
		getJobRepository().updateExecutionContext(stepExecution);
	} catch (Exception e) {
		stepExecution.setStatus(BatchStatus.UNKNOWN);
		exitStatus = exitStatus.and(ExitStatus.UNKNOWN);
		stepExecution.addFailureException(e);
	}

	stepExecution.setEndTime(new Date());
	stepExecution.setExitStatus(exitStatus);

	try {
		getJobRepository().update(stepExecution);
	}
	catch (Exception e) {
		stepExecution.setStatus(BatchStatus.UNKNOWN);
		stepExecution.setExitStatus(exitStatus.and(ExitStatus.UNKNOWN));
		stepExecution.addFailureException(e);
	}

	try {
		close(stepExecution.getExecutionContext());
	}
	catch (Exception e) {
		stepExecution.addFailureException(e);
	}
	doExecutionRelease();

2. Step业务执行doExecute

doExecute方法在抽象类AbstractStep中并未定义,单线程执行方式是在
TaskletStep中执行的

2.1. 开始执行的准备工作

  • 设置信息到StepExecutionContext
  • 调用stream接口的update方法
  • 更新StepExecutionContext到资源库
  • 创建信号类
stepExecution.getExecutionContext().put(TASKLET_TYPE_KEY, tasklet.getClass().getName());
	stepExecution.getExecutionContext().put(STEP_TYPE_KEY, this.getClass().getName());
	
	stream.update(stepExecution.getExecutionContext());
	
	getJobRepository().updateExecutionContext(stepExecution);
	
	final Semaphore semaphore = createSemaphore();

2.2. 使用重复执行处理类RepeatTemplate开始执行业务处理

stepOperations.iterate(new StepContextRepeatCallback(stepExecution) {

		@Override
		public RepeatStatus doInChunkContext(RepeatContext repeatContext, ChunkContext chunkContext) throws Exception {

			StepExecution stepExecution = chunkContext.getStepContext().getStepExecution();
			interruptionPolicy.checkInterrupted(stepExecution);

			RepeatStatus result = new TransactionTemplate(transactionManager, transactionAttribute)
				.execute(new ChunkTransactionCallback(chunkContext, semaphore));
		
			chunkListener.afterChunk(chunkContext);
			interruptionPolicy.checkInterrupted(stepExecution);
			return result;
		}

	});

3. 启动RepeatTemplate迭代iterate方法

3.1. 开始执行迭代方法iterate

  • 同步管理器获取RepeatContext
  • 初始化Repeat状态为CONTINUABLE
  • 执行业务数据
  • 处理同步管理器
public RepeatStatus iterate(RepeatCallback callback) {

		RepeatContext outer = RepeatSynchronizationManager.getContext();

		RepeatStatus result = RepeatStatus.CONTINUABLE;
		try {
			result = executeInternal(callback);
		} finally {
			RepeatSynchronizationManager.clear();
			if (outer != null) {
				RepeatSynchronizationManager.register(outer);
			}
		}
		return result;
	}

3.2. 开始执行内部逻辑 executeInternal方法

  1. 开始执行前的准备工作
  • 检查状态是否是执行中
  • 触发RepeatListeneropen方法
  • 初始化一些状态属性结果等变量
RepeatContext context = start();
		boolean running = !isMarkedComplete(context);
		for (RepeatListener interceptor : listeners) {
			interceptor.open(context);
			running = running && !isMarkedComplete(context);
			if (!running)
				break;
		}

		RepeatStatus result = RepeatStatus.CONTINUABLE;

		RepeatInternalState state = createInternalState(context);

		Collection<Throwable> throwables = state.getThrowables();

		Collection<Throwable> deferred = new ArrayList<>();
  1. 执行迭代
  • 触发RepeatListenerbefore方法
  • 判断状态,如果还是running 调用getNextResult获取结果
  • 判断完成的依据是走的CompletionPolicy结构的方法
while (running) {
		for (int i = 0; i < listeners.length; i++) {
			RepeatListener interceptor = listeners[i];
			interceptor.before(context);
			running = running && !isMarkedComplete(context);
		}

		if (running) {
			try {
				result = getNextResult(context, callback, state);
				executeAfterInterceptors(context, result);
			} catch (Throwable throwable) {
				doHandle(throwable, context, deferred);
			}
			if (isComplete(context, result) || isMarkedComplete(context) || !deferred.isEmpty()) {
				running = false;
			}
		}
	}

	result = result.and(waitForResults(state));
	for (Throwable throwable : throwables) {
		doHandle(throwable, context, deferred);
	}
	state = null;
  1. getNextResult中调用callBack的doInteration方法
protected RepeatStatus getNextResult(RepeatContext context, RepeatCallback callback, RepeatInternalState state)
			throws Throwable {
		update(context);
		return callback.doInIteration(context);
	}

3.3. StepContextRepeatCallback 执行流程

  1. 执行doInIteration
  • 在同步管理器中获取StepContext
  • 在队列中获取一个chunkContext 如果为空创建一个
  • 执行doInChunkContext
  • 如果执行失败重新加到队列
  • 关闭Step同步管理器
StepContext stepContext = StepSynchronizationManager.register(stepExecution);
	ChunkContext chunkContext = attributeQueue.poll();
	if (chunkContext == null) {
		chunkContext = new ChunkContext(stepContext);
	}

	try {
		return doInChunkContext(context, chunkContext);
	} finally {
		if (!chunkContext.isComplete()) {
			attributeQueue.add(chunkContext);
		}
		StepSynchronizationManager.close();
	}
  1. 执行doInChunkContext 这段代码是在2.2中出现过的
  • 前期准备检查StepExecution
  • 执行事物模板
  • 触发chunkListener的afterChunk方法
  • 检查stepExecution
StepExecution stepExecution = chunkContext.getStepContext().getStepExecution();
	interruptionPolicy.checkInterrupted(stepExecution);

	RepeatStatus result = new TransactionTemplate(transactionManager, transactionAttribute)
		.execute(new ChunkTransactionCallback(chunkContext, semaphore));

	chunkListener.afterChunk(chunkContext);
	interruptionPolicy.checkInterrupted(stepExecution);
	return result;

3.4 执行TransactionTemplate的execute方法

  1. 执行事务操作
  • 获取一个事物
  • 在事物中执行业务逻辑
  • 提交事务
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
		return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
	} else {
		TransactionStatus status = this.transactionManager.getTransaction(this);
		T result = action.doInTransaction(status);
		this.transactionManager.commit(status);
		return result;
	}

2.在事物中执行业务逻辑 Tasklet.ChunkTransactionCallback.doInTransaction

  • 同步管理器注册
  • 初始化一些属性
  • 触发chunkListener的beforeChunk方法
  • copy一份stepExecution到旧版本
  • 执行tasklet
  • 执行Stream接口的update方法
  • 更新资源库中的内容
TransactionSynchronizationManager.registerSynchronization(this);

	RepeatStatus result = RepeatStatus.CONTINUABLE;

	StepContribution contribution = stepExecution.createStepContribution();

	chunkListener.beforeChunk(chunkContext);

	oldVersion = new StepExecution(stepExecution.getStepName(), stepExecution.getJobExecution());
	copy(stepExecution, oldVersion);

	try {
		result = tasklet.execute(contribution, chunkContext);
		if (result == null) {
			result = RepeatStatus.FINISHED;
		}

	} finally {
		semaphore.acquire();
		locked = true;
		stepExecution.apply(contribution);
	}

	stepExecutionUpdated = true;

	stream.update(stepExecution.getExecutionContext());
    getJobRepository().updateExecutionContext(stepExecution);
	stepExecution.incrementCommitCount();
	getJobRepository().update(stepExecution);

	return result;

3.4 执行Tasklet的execute方法

这儿的Tasklet可能是我们自己定义的,如果有读写chunk的那么实现类是ChunkOrientedTasklet

  • 调用chunkProvider.provide读取数据
  • 处理读取到的数据
  • 提交处理完成的数据
Chunk<I> inputs = (Chunk<I>) chunkContext.getAttribute(INPUTS_KEY);
	if (inputs == null) {
		inputs = chunkProvider.provide(contribution);
		if (buffering) {
			chunkContext.setAttribute(INPUTS_KEY, inputs);
		}
	}

	chunkProcessor.process(contribution, inputs);
	chunkProvider.postProcess(contribution, inputs);

	if (inputs.isBusy()) {
		return RepeatStatus.CONTINUABLE;
	}
	chunkContext.removeAttribute(INPUTS_KEY);
	chunkContext.setComplete();
	return RepeatStatus.continueIf(!inputs.isEnd());