审批流程图
如下图,在此流程图中,存在两个UserTask节点,第一个节点是主管审批,第二个节点是产品经理审批,两个节点中间有一个排他网关,此网关用来对主管审批的结果进行判断,如果主管审批通过,则流程走到产品经理审批节点,如果主管审批拒绝,则流程走到结束节点。
主管审批节点通过UEL表达式${assignManager}动态赋值,产品经理审批节点通过UEL表达式${assignProductLineManager}动态赋值,网关节点通过UEL表达式${isPass}动态赋值。
节点行为
上文提到,流程流转到 UserTask 节点后,准备执行该节点上的行为,该节点的行为对应的类是 UserTaskActivityBehavior,入口为 executeActivityBehavior(ActivityBehavior, FlowNode)。
/*** 同步执行* @param flowNode*/
protected void executeSynchronous(FlowNode flowNode) {// 省略部分代码// 执行实际的行为,UserTask对应的behavior是UserTaskActivityBehavior,// 这个UserTaskActivityBehavior里面会把task写入到act_ru_taskActivityBehavior activityBehavior = (ActivityBehavior) flowNode.getBehavior();// 当 activityBehavior 不为空,走此方法,此方法后续也会调用 planTakeOutgoingSequenceFlowsOperation// activityBehavior 表示一个节点上拥有的行为// StartEvent 节点的行为是 NoneStartEventActivityBehavior,没有做其它业务,仅仅是过度// UserTask 节点的行为是 UserTaskActivityBehavior,这个行为会把任务写入到数据库后,等待用户完成任务,流程才会继续走下去if (activityBehavior != null) {executeActivityBehavior(activityBehavior, flowNode);} else {logger.debug("No activityBehavior on activity '{}' with execution {}", flowNode.getId(), execution.getId());// 计划执行 TakeOutgoingSequenceFlows 操作,这个操作是一个连线行为,第一步先找出当前节点的出口,第二步从出口走到下一个节点。Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(execution, true);}
}
ContinueProcessOperation 中的 executeActivityBehavior(ActivityBehavior, FlowNode) 方法实现如下,这里参数 activityBehavior 的值是 UserTaskActivityBehavior 对象的实例。
/*** 执行节点上的行为* @param activityBehavior* @param flowNode*/
protected void executeActivityBehavior(ActivityBehavior activityBehavior,FlowNode flowNode) {logger.debug("Executing activityBehavior {} on activity '{}' with execution {}",activityBehavior.getClass(),flowNode.getId(),execution.getId());if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createActivityEvent(ActivitiEventType.ACTIVITY_STARTED,flowNode.getId(),flowNode.getName(),execution.getId(),execution.getProcessInstanceId(),execution.getProcessDefinitionId(),flowNode));}try {// 这方法里面后续会执行 planTakeOutgoingSequenceFlowsOperationactivityBehavior.execute(execution);} catch (RuntimeException e) {if (LogMDC.isMDCEnabled()) {LogMDC.putMDCExecution(execution);}throw e;}
}
UserTaskActivityBehavior 中的 execute(DelegateExecution) 方法实现如下:
public class UserTaskActivityBehavior extends TaskActivityBehavior {// 省略部分代码protected UserTask userTask;// 在部署流程的时候,会把 bpmn20.xml 上解析到的 userTask 传入构造函数中public UserTaskActivityBehavior(UserTask userTask) {this.userTask = userTask;}public void execute(DelegateExecution execution) {CommandContext commandContext = Context.getCommandContext();TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();// 创建任务,这个 TaskEntity 将会存储在表 act_ru_task 中TaskEntity task = taskEntityManager.create();task.setExecution((ExecutionEntity) execution);task.setTaskDefinitionKey(userTask.getId());// 声明变量,用于临时存储 bpmn20.xml 上 userTask 定义的变量信息,见下面的 图 1.0String activeTaskName = null;String activeTaskDescription = null;String activeTaskDueDate = null;String activeTaskPriority = null;String activeTaskCategory = null;String activeTaskFormKey = null;String activeTaskSkipExpression = null;String activeTaskAssignee = null;String activeTaskOwner = null;List<String> activeTaskCandidateUsers = null;List<String> activeTaskCandidateGroups = null;ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();if (Context.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {// 省去部分代码 } else {// 这里的 userTask 解析自 bpmn20.xml 文件中定义的 UseTask 节点activeTaskName = userTask.getName();activeTaskDescription = userTask.getDocumentation();activeTaskDueDate = userTask.getDueDate();activeTaskPriority = userTask.getPriority();activeTaskCategory = userTask.getCategory();activeTaskFormKey = userTask.getFormKey();activeTaskSkipExpression = userTask.getSkipExpression();activeTaskAssignee = userTask.getAssignee();activeTaskOwner = userTask.getOwner();activeTaskCandidateUsers = userTask.getCandidateUsers();activeTaskCandidateGroups = userTask.getCandidateGroups();}// 省去部分代码 /*** 任务写入 act_ru_task 表中,但只是暂时存到缓存中,后面才会写入数据库*/taskEntityManager.insert(task, (ExecutionEntity) execution);// 省去部分代码 boolean skipUserTask = false;if (StringUtils.isNotEmpty(activeTaskSkipExpression)) {Expression skipExpression = expressionManager.createExpression(activeTaskSkipExpression);skipUserTask = SkipExpressionUtil.isSkipExpressionEnabled(execution, skipExpression) && SkipExpressionUtil.shouldSkipFlowElement(execution, skipExpression);}// Handling assignments need to be done after the task is inserted, to have an idif (!skipUserTask) {// 处理UserTask节点中设置的UEL变量表达式,Assignee、CandidateUsers、CandidateGroups都是在这里解析handleAssignments(taskEntityManager, activeTaskAssignee, activeTaskOwner, activeTaskCandidateUsers, activeTaskCandidateGroups, task, expressionManager, execution);}// 如果有监听 UserTask 创建事件的监听器,就执行该监听器processEngineConfiguration.getListenerNotificationHelper().executeTaskListeners(task, TaskListener.EVENTNAME_CREATE);// 省去部分代码 // 如果 skipUserTask 是true,说明任务不会在UserTask节点等待用户审批,而是直接就走向下个节点// 没有设置跳过 UserTask 节点,所以 skipUserTask == false,不会走下面这个逻辑if (skipUserTask) {taskEntityManager.deleteTask(task, null, false, false);leave(execution);}}
}
图 1.0
总结
UserTask 节点上的 UserTaskActivityBehavior 行为,主要工作是解析 bpmn20.xml 流程文件上定义的 UserTask 节点变量信息,得到变量信息后,从 ExecutionEntity 上匹配变量的值,把匹配到的值设置到 TaskEntity 中。将 TaskEntity 存储入库,得益于未设置 skipExpression(跳过表达式),使得流程从 StartEvent 开始后流转到了 UserTask 节点,并在 UserTask 节点上暂时停了下来等待,直到用户完成审批,流程才会继续往下走。