activiti学习(二十一)——流程虚拟机源码分析(三)——从进入到离开userTask

前言

承接上文《activiti学习(二十)——流程虚拟机源码分析(二)——从开始节点离开到下个节点前》,假设execution接下来进入的节点是userTask,本文分析一下进入userTask的准备工作,到执行userTask的行为类,最后客户端调用taskService.complete方法离开userTask的过程。

 

准备工作

承接上文,会调用AtomicOperationTransitionCreateScope类:

public class AtomicOperationTransitionCreateScope implements AtomicOperation {

//......

  public void execute(InterpretableExecution execution) {
    InterpretableExecution propagatingExecution = null;
    ActivityImpl activity = (ActivityImpl) execution.getActivity();
    if (activity.isScope()) {
//......
    } else {
      propagatingExecution = execution;
    }

    propagatingExecution.performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_START);
  }
}

由于userTask的activityImpl的isScope为false,因此单纯以当前execution调用performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_START)。跟踪AtomicOperationTransitionNotifyListenerStart类:

public class AtomicOperationTransitionNotifyListenerStart extends AbstractEventAtomicOperation {
  
//......

  protected String getEventName() {
    return org.activiti.engine.impl.pvm.PvmEvent.EVENTNAME_START;
  }

  protected void eventNotificationsCompleted(InterpretableExecution execution) {
    TransitionImpl transition = execution.getTransition();
    ActivityImpl destination = null;
    if(transition == null) { // this is null after async cont. -> transition is not stored in execution
      destination = (ActivityImpl) execution.getActivity();
    } else {
      destination = transition.getDestination();
    }    
    ActivityImpl activity = (ActivityImpl) execution.getActivity();
    if (activity!=destination) {
      ActivityImpl nextScope = AtomicOperationTransitionNotifyListenerTake.findNextScope(activity, destination);
      execution.setActivity(nextScope);
      execution.performOperation(TRANSITION_CREATE_SCOPE);
    } else {
      execution.setTransition(null);
      execution.setActivity(destination);
      execution.performOperation(ACTIVITY_EXECUTE);
    }
  }
}

首先execution的performOperation调用会触发执行监听器获取AtomicOperationTransitionNotifyListenerStart的getEventName对应的事件,这里是start事件,然后触发执行监听器的start事件。不记得performOperation调用逻辑的可回顾《activiti学习(十九)——流程虚拟机源码分析(一)——流程启动源码分析》“流程实例启动”的小节。第10行获取execution当前的连线,此时连线非空,且destination就是当前的ActivityImpl,回顾上文《activiti学习(二十)——流程虚拟机源码分析(二)——从开始节点离开到下个节点前》可知我们刚刚就是从这条连线过来,并且未作变更。因此18行判断为false,执行23-25行代码,23行设置execution当前连线为null,24行设置当前活动为连线终点的活动,按本文的假设,即userTask,25行调用execution.performOperation(ACTIVITY_EXECUTE)。回顾《activiti学习(十九)》可知该原子操作触发全局事件转发器的ACTIVITY_STARTED事件,然后调用当前活动的行为类,这里会调用userTask的行为类UserTaskActivityBehavior。

 

userTask行为类

进入userTask行为类

  public void execute(ActivityExecution execution) throws Exception {
    TaskEntity task = TaskEntity.createAndInsert(execution);
    task.setExecution(execution);
    
    Expression activeNameExpression = null;
    Expression activeDescriptionExpression = null;
    Expression activeDueDateExpression = null;
    Expression activePriorityExpression = null;
    Expression activeCategoryExpression = null;
    Expression activeFormKeyExpression = null;
    Expression activeSkipExpression = null;
    Expression activeAssigneeExpression = null;
    Expression activeOwnerExpression = null;
    Set<Expression> activeCandidateUserExpressions = null;
    Set<Expression> activeCandidateGroupExpressions = null;
    
    if (Context.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {
//......      
    } else {
      activeNameExpression = taskDefinition.getNameExpression();
      activeDescriptionExpression = taskDefinition.getDescriptionExpression();
      activeDueDateExpression = taskDefinition.getDueDateExpression();
      activePriorityExpression = taskDefinition.getPriorityExpression();
      activeCategoryExpression = taskDefinition.getCategoryExpression();
      activeFormKeyExpression = taskDefinition.getFormKeyExpression();
      activeSkipExpression = taskDefinition.getSkipExpression();
      activeAssigneeExpression = taskDefinition.getAssigneeExpression();
      activeOwnerExpression = taskDefinition.getOwnerExpression();
      activeCandidateUserExpressions = taskDefinition.getCandidateUserIdExpressions();
      activeCandidateGroupExpressions = taskDefinition.getCandidateGroupIdExpressions();
    }
    
    task.setTaskDefinition(taskDefinition);

//......task属性设置
    
    boolean skipUserTask = SkipExpressionUtil.isSkipExpressionEnabled(execution, activeSkipExpression) &&
        SkipExpressionUtil.shouldSkipFlowElement(execution, activeSkipExpression);
    
    if (!skipUserTask) {
      handleAssignments(activeAssigneeExpression, activeOwnerExpression, activeCandidateUserExpressions, 
        activeCandidateGroupExpressions, task, execution);
    }

    task.fireEvent(TaskListener.EVENTNAME_CREATE);

    if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
      Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
        ActivitiEventBuilder.createEntityEvent(ActivitiEventType.TASK_CREATED, task));
    }

    if (skipUserTask) {
      task.complete(null, false);
    }
  }

第2行创建task实体类并放入缓存中,17行判断是否有开启流程定义节点缓存,若没有则执行20-30行单纯获取对象解析时节点的属性。35行省略把获取的节点属性设置到task实体中。37行获取是否满足跳过任务的表达式,如果不满足,则40行执行assignee、candidateGroup、candidateUser等属性的设置,并且触发任务监听器的assignment事件。45行触发任务监听器的create事件。47-50行触发全局事件转发器的TASK_CREATED事件。52行判断若满足跳过任务条件,则直接执行task的complete方法完成任务。至此,流程虚拟机完成了《activiti学习(十九)》中执行StartProcessInstanceCmd命令并返回。所有插入缓存的实体例如ExecutionEntity和TaskEntity等被刷新到数据库中。

 

离开userTask

通常用户是通过调用TaskService.complete方法提交一个userTask,接下来我们跟踪代码是怎么提交并离开userTask。TaskService.complete方法会调用CompleteTaskCmd命令,我们跟踪CompleteTaskCmd类:

public class CompleteTaskCmd extends NeedsActiveTaskCmd<Void> {
      
//......
  
  protected Void execute(CommandContext commandContext, TaskEntity task) {
    if (variables!=null) {
    	if (localScope) {
    		task.setVariablesLocal(variables);
    	} else if (task.getExecutionId() != null) {
    		task.setExecutionVariables(variables);
    	} else {
    		task.setVariables(variables);
    	}
    }
    
    task.complete(variables, localScope);
    return null;
  }

//......
}

16行调用taskEntity的complete方法,我们接着跟踪TaskEntity类:

public class TaskEntity extends VariableScopeImpl implements Task, DelegateTask, Serializable, PersistentObject, HasRevision, BulkDeleteable {

//......

  public void complete(Map variablesMap, boolean localScope) {
  	
  	if (getDelegationState() != null && getDelegationState().equals(DelegationState.PENDING)) {
  		throw new ActivitiException("A delegated task cannot be completed, but should be resolved instead.");
  	}
  	
    fireEvent(TaskListener.EVENTNAME_COMPLETE);

    if (Authentication.getAuthenticatedUserId() != null && processInstanceId != null) {
      getProcessInstance().involveUser(Authentication.getAuthenticatedUserId(), IdentityLinkType.PARTICIPANT);
    }
    
    if(Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
    	Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
    	    ActivitiEventBuilder.createEntityWithVariablesEvent(ActivitiEventType.TASK_COMPLETED, this, variablesMap, localScope));
    }
 
    Context
      .getCommandContext()
      .getTaskEntityManager()
      .deleteTask(this, TaskEntity.DELETE_REASON_COMPLETED, false);
    
    if (executionId!=null) {
      ExecutionEntity execution = getExecution();
      execution.removeTask(this);
      execution.signal(null, null);
    }
  }

//......
}

11行触发任务监听器complete事件。13-15行设置IdentityLinkEntity,对应act_ru_identityLink表,注意在上一小节handleAssignments函数时,也会调用类似的函数,把assignee设置到IdentityLinkEntity中,这里会检查如果有相同的userId则返回而不会重复插入。17-20行触发全局事件转发器的TASK_COMPLETED事件。22-25行删除task。30行调用execution.signal,我们跟踪ExecutionEntity类:

 public class ExecutionEntity extends VariableScopeImpl implements ActivityExecution, ExecutionListenerExecution, Execution, PvmExecution, 
	ProcessInstance, InterpretableExecution, PersistentObject, HasRevision {

//......

  public void signal(String signalName, Object signalData) {
    ensureActivityInitialized();
    SignallableActivityBehavior activityBehavior = (SignallableActivityBehavior) activity.getActivityBehavior();
    try {
    	String signalledActivityId = activity.getId();
      activityBehavior.signal(this, signalName, signalData);
      
      // If needed, dispatch an event indicating an activity was signalled
      boolean isUserTask = (activityBehavior instanceof UserTaskActivityBehavior)
      		|| ((activityBehavior instanceof MultiInstanceActivityBehavior) 
      				&& ((MultiInstanceActivityBehavior) activityBehavior).getInnerActivityBehavior() instanceof UserTaskActivityBehavior);
      
      if(!isUserTask && Context.getProcessEngineConfiguration() != null 
      		&& Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
      	Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createSignalEvent(
      		ActivitiEventType.ACTIVITY_SIGNALED, signalledActivityId, signalName, signalData, this.id, this.processInstanceId, this.processDefinitionId));
      }
      
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new PvmException("couldn't process signal '"+signalName+"' on activity '"+activity.getId()+"': "+e.getMessage(), e);
    }
  }
 
//......
}

第7行确保execution当前的活动不为空。第8行获取当前活动的行为类。11行调用行为类的signal方法。14行获取isUserTask是非值,这里显然activityBehavior就是UserTaskActivityBehavior,因此为true,所以不会执行18-22行的事件转发。我们跟踪UserTaskActivityBehavior的signal方法:

public class UserTaskActivityBehavior extends TaskActivityBehavior {

//......

  public void signal(ActivityExecution execution, String signalName, Object signalData) throws Exception {
    if (!((ExecutionEntity) execution).getTasks().isEmpty())
      throw new ActivitiException("UserTask should not be signalled before complete");
    leave(execution);
  }

//......
}

signal方法调用leave离开userTask,这里调用AbstractBpmnActivityBehavior的leave方法,跟踪AbstractBpmnActivityBehavior类:

public class AbstractBpmnActivityBehavior extends FlowNodeActivityBehavior {

//......

  protected void leave(ActivityExecution execution) {
    if(hasCompensationHandler(execution)) {
      createCompensateEventSubscription(execution);
    }
    if (!hasLoopCharacteristics()) {
      super.leave(execution);
    } else if (hasMultiInstanceCharacteristics()){
      multiInstanceActivityBehavior.leave(execution);
    }
  }

//......
}

第6行判断userTask是否设置isForCompensation, userTask默认不设置,这里先不细述。第9行判断是否为多实例任务,这里我们假设userTask不是多实例任务,则走第10行,调用FlowNodeActivityBehavior的leave:

public abstract class FlowNodeActivityBehavior implements SignallableActivityBehavior {

//......

  protected void leave(ActivityExecution execution) {
    bpmnActivityBehavior.performDefaultOutgoingBehavior(execution);
  }

//......
}

这里只是简单调用BpmnActivityBehavior的performDefaultOutgoingBehavior方法,跟踪BpmnActivityBehavior:

public class BpmnActivityBehavior implements Serializable {

//......

  public void performDefaultOutgoingBehavior(ActivityExecution activityExecution) {
    ActivityImpl activity = (ActivityImpl) activityExecution.getActivity();
    if (!(activity.getActivityBehavior() instanceof IntermediateCatchEventActivityBehavior)) {
      dispatchJobCanceledEvents(activityExecution);
    }
    performOutgoingBehavior(activityExecution, true, false, null);
  }

  protected void performOutgoingBehavior(ActivityExecution execution, 
          boolean checkConditions, boolean throwExceptionIfExecutionStuck, List<ActivityExecution> reusableExecutions) {
//......

    String defaultSequenceFlow = (String) execution.getActivity().getProperty("default");
    List<PvmTransition> transitionsToTake = new ArrayList<PvmTransition>();

    List<PvmTransition> outgoingTransitions = execution.getActivity().getOutgoingTransitions();
    for (PvmTransition outgoingTransition : outgoingTransitions) {
      Expression skipExpression = outgoingTransition.getSkipExpression();
      
      if (!SkipExpressionUtil.isSkipExpressionEnabled(execution, skipExpression)) {
        if (defaultSequenceFlow == null || !outgoingTransition.getId().equals(defaultSequenceFlow)) {
          Condition condition = (Condition) outgoingTransition.getProperty(BpmnParse.PROPERTYNAME_CONDITION);
          if (condition == null || !checkConditions || condition.evaluate(outgoingTransition.getId(), execution)) {
            transitionsToTake.add(outgoingTransition);
          }
        }
        
      } else if (SkipExpressionUtil.shouldSkipFlowElement(execution, skipExpression)){
        transitionsToTake.add(outgoingTransition);
      }
    }

    if (transitionsToTake.size() == 1) {
      execution.take(transitionsToTake.get(0));
    } else if (transitionsToTake.size() >= 1) {
      execution.inactivate();
      if (reusableExecutions == null || reusableExecutions.isEmpty()) {
        execution.takeAll(transitionsToTake, Arrays.asList(execution));
      } else {
        execution.takeAll(transitionsToTake, reusableExecutions);
      }
    } else {
//......
    }
  }

//......
}

第7行判断为非,直接执行第10行,跳转到13行的函数中。20行获取userTask的“出线”。25-29行判断当满足“出线”条件时,把“出线”加入到待离开的连线集合中。32-34行判断若满足跳过节点条件,也加入待离开的连线集合中。若待离开的连线集合数量是1,则执行38行execution.take离开,否则执行execution.takeAll离开。关于execution的take和takeAll,在《activiti学习(二十)》中分析过,不了解的同学可以去看一下。

 

小结

本文对于审批流程自由跳转来说是非常重要的预热环节,这里集中了一个普通的用户任务离开时会做什么,进入时会做什么。由于activiti没有提供流程自由跳转的api,我们必须手动去实现这种效果。关于如何实现,留到下一篇文章中再讲。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要扩展 Activiti UserTask 节点并实现自定义节点属性,可以按照以下步骤进行: 1. 创建一个 Java 类来扩展 UserTask 节点。该类需要继承 org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior 类。 例如: ``` public class CustomUserTaskBehavior extends UserTaskActivityBehavior { // 自定义节点属性 } ``` 2. 在该类中添加自定义节点属性。 例如: ``` public class CustomUserTaskBehavior extends UserTaskActivityBehavior { private String customAttribute; public void setCustomAttribute(String customAttribute) { this.customAttribute = customAttribute; } public String getCustomAttribute() { return customAttribute; } } ``` 3. 创建一个 BpmnParseHandler 类来解析扩展属性。该类需要继承 org.activiti.engine.impl.bpmn.parser.AbstractBpmnParseHandler 类。 例如: ``` public class CustomUserTaskBpmnParseHandler extends AbstractBpmnParseHandler<UserTask> { @Override protected Class<? extends BaseElement> getHandledType() { return UserTask.class; } @Override protected void executeParse(BpmnParse bpmnParse, UserTask userTask) { CustomUserTaskBehavior customUserTaskBehavior = new CustomUserTaskBehavior(); // 解析自定义节点属性 String customAttribute = userTask.getAttributes().getValue("customAttribute"); customUserTaskBehavior.setCustomAttribute(customAttribute); userTask.setBehavior(customUserTaskBehavior); } } ``` 4. 在流程引擎配置中注册 BpmnParseHandler 类。 例如: ``` ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration(); configuration.setCustomDefaultBpmnParseHandlers(Collections.singletonList(new CustomUserTaskBpmnParseHandler())); ``` 现在,你已经成功扩展了 Activiti UserTask 节点并实现了自定义节点属性。在 BPMN 文件中,你可以使用自定义属性来配置 UserTask 节点,例如: ``` <userTask id="task1" name="Task 1" activiti:assignee="john" customAttribute="customValue"></userTask> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值