審批流程圖
????????如下圖,在此流程圖中,存在兩個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 節點上暫時停了下來等待,直到用戶完成審批,流程才會繼續往下走。