activiti流程运行过程代码走读

1. 目的

本文将对流程在activiti中是怎么运行的,任务是怎样推动的进行讲解。

主要包括以下内容:

  1. PVM中怎么表示流程、任务、连接线,它和activiti的Model怎样转换的。
  • 启动流程实例,怎么从开始节点流转到下一个节点。

  • 怎样监听流程事件。

2. 主要的jar包和java类

pvm的实现在包org.activiti.engine.impl.pvm中,我通过源码跟踪、阅读,分析出PVM有以下重要的类:

class 功能
ProcessDefinitionImpl 流程定义
ExecutionEntity 管理流程的运行
ActivityImpl 流程节点的定义
AtomicOperation 流程运行方法,如:
 AtomicOperationActivityStart(流程启动),
 AtomicOperationActivityEnd(流程结束)
ActivityBehavior 委托

2.1 在哪定义的

2.1.1 ProcessDefinitionImpl

ProcessDefinitionImpl是PVM对整个流程定义。通过ProcessDefinitionImpl.createProcessInstance可以得到流程实例管理接口PvmProcessInstanceProcessDefinitionImpl的代码片段如下:

  public class ProcessDefinitionImpl extends ScopeImpl implements PvmProcessDefinition {

    private static final long serialVersionUID = 1L;

    protected String name;
    protected String key;
    protected String description;
    protected ActivityImpl initial;
    protected Map<ActivityImpl, List<ActivityImpl>> initialActivityStacks = new HashMap<ActivityImpl, List<ActivityImpl>>();
    protected List<LaneSet> laneSets;
    protected ParticipantProcess participantProcess;

    public ProcessDefinitionImpl(String id) {
      super(id, null);
      processDefinition = this;
    }

    public PvmProcessInstance createProcessInstance() {
      if(initial == null) {
        throw new ActivitiException("Process '"+name+"' has no default start activity (e.g. none start event), hence you cannot use 'startProcessInstanceBy...' but have to start it using one of the modeled start events (e.g. message start events).");
      }
      return createProcessInstanceForInitial(initial);
    }

    ...  
  }

2.1.2 ExecutionEntity

ExecutionEntity实现了接口ActivityExecutionActivityExecution是流程运行管理接口。ExecutionEntity提供的功能如下:

  1. 启动、结束、销毁流程。
  • 对流程元素ActivityImpl的管理(添加删除修改父节点、实例ID、任务等)。

ExecutionEntity里几个重要的方法:

  1. initialize()里面初始化task、job、variable、event。
  • start()是流程启动方法。

  • performOperation()是流程执行方法,流程的推动都调用performOperation()

2.1.3 ActivityImpl

ActivityImpl表示单个流程元素,比如任务、开始节点、连接线、网关等。它的属性包括:variables、activityBehavior、incomingTransitions、outgoingTransitions以及元素界面位置等。ActivityImpl的类图如下:

类图

  • ActivityImpl是活动节点,在流程图上对应开始节点、结束节点、各种任务节点。

  • TransitionImpl是连接线。

  • ProcessDefinitionImpl是整个的定义,类图中未画。类ProcessElementImpl里面有ProcessDefinitionImpl属性。

2.1.4 AtomicOperation

AtomicOperation是流程执行的接口,比如流程启动,流程结束,任务启动,任务执行,任务结束等。AtomicOperation中枚举了所有流程执行方法,AtomicOperation的代码如下:


  public interface AtomicOperation {

    AtomicOperation PROCESS_START = new AtomicOperationProcessStart();
    AtomicOperation PROCESS_START_INITIAL = new AtomicOperationProcessStartInitial();
    AtomicOperation PROCESS_END = new AtomicOperationProcessEnd();
    AtomicOperation ACTIVITY_START = new AtomicOperationActivityStart();
    AtomicOperation ACTIVITY_EXECUTE = new AtomicOperationActivityExecute();
    AtomicOperation ACTIVITY_END = new AtomicOperationActivityEnd();
    AtomicOperation TRANSITION_NOTIFY_LISTENER_END = new AtomicOperationTransitionNotifyListenerEnd();
    AtomicOperation TRANSITION_DESTROY_SCOPE = new AtomicOperationTransitionDestroyScope();
    AtomicOperation TRANSITION_NOTIFY_LISTENER_TAKE = new AtomicOperationTransitionNotifyListenerTake();
    AtomicOperation TRANSITION_CREATE_SCOPE = new AtomicOperationTransitionCreateScope();
    AtomicOperation TRANSITION_NOTIFY_LISTENER_START = new AtomicOperationTransitionNotifyListenerStart();

    AtomicOperation DELETE_CASCADE = new AtomicOperationDeleteCascade();
    AtomicOperation DELETE_CASCADE_FIRE_ACTIVITY_END = new AtomicOperationDeleteCascadeFireActivityEnd();

    void execute(InterpretableExecution execution);

    boolean isAsync(InterpretableExecution execution);
  }

2.1.5 ActivityBehavior

ActivityBehavior是委托接口。AtomicOperation执行过程中会调用ActivityBehaviorActivityBehavior定义了execute方法,入参类型为ActivityExecutionActivityBehavior的代码如下:

public interface ActivityBehavior extends Serializable {
  void execute(ActivityExecution execution) throws Exception;
}

2.2 模块之间调用顺序

下面用RuntimeServiceImpl.startProcessInstanceById()启动一个流程,说明PVM的调用顺序。流程图如下:

示例

2.2.1 从activiti调用PVM

RuntimeServiceImpl.startProcessInstanceById()通过命令模式调用了方法StartProcessInstanceCmd.execute()StartProcessInstanceCmd实现了以下功能:

  1. 从数据库获取ProcessDefinitionEntityProcessDefinitionEntity是流程对应的数据库实体,同时继承ProcessDefinitionImpl)。
  • 通过方法ProcessDefinitionEntity.createProcessInstance获得ExecutionEntity

  • 调用ExecutionEntity.start()启动流程。

2.2.2 ExecutionEntity调用AtomicOperation

<a id="start"></a>
StartProcessInstanceCmd调用了ExecutionEntity.start()就完了,任务怎么生成的。肯定在ExecutionEntity.start()里。ExecutionEntity.start()的代码如下:

  public void start() {
    if(startingExecution == null && isProcessInstanceType()) {
      startingExecution = new StartingExecution(processDefinition.getInitial());
    }
    performOperation(AtomicOperation.PROCESS_START);
  }

ExecutionEntity.start()里面调用了performOperationperformOperation又对同步执行和异步执行进行了拆分,这里只看同步执行的代码:

//  activiti里面到处都是`CommandContext`
protected void performOperationSync(AtomicOperation executionOperation) {
  Context
    .getCommandContext()
    .performOperation(executionOperation, this);
}

Context.getCommandContext().performOperation里面调用了executionOperation.execute()Context里对线程之间的数据进行了隔离,但performOperation对并发调用的判断是多余的。一次部署过程需要调用10多次performOperation,很有必要看看代码长什么样,Context.getCommandContext().performOperation的代码如下:

  public void performOperation(AtomicOperation executionOperation, InterpretableExecution execution) {
    nextOperations.add(executionOperation);
    if (nextOperations.size()==1) {
      try {
        Context.setExecutionContext(execution);
        while (!nextOperations.isEmpty()) {
          AtomicOperation currentOperation = nextOperations.removeFirst();
          if (log.isTraceEnabled()) {
            log.trace("AtomicOperation: {} on {}", currentOperation, this);
          }
          if (execution.getReplacedBy() == null) {
            currentOperation.execute(execution);
          } else {
            currentOperation.execute(execution.getReplacedBy());
          }
        }
      } finally {
        Context.removeExecutionContext();
      }
    }
  }

2.2.3 AtomicOperation执行顺序

绕了一大圈,ExecutionEntity.start()真正调用了AtomicOperation.PROCESS_START(AtomicOperation.PROCESS_START = new AtomicOperationProcessStart())。AtomicOperationProcessStart实现了以下功能:

  1. 触发listener、event。
  • 设置流程运行节点为开始节点。

  • 调用AtomicOperation.PROCESS_START_INITIAL

AtomicOperationProcessStart的代码片段如下:

@Override
  protected void eventNotificationsCompleted(InterpretableExecution execution) {
    if(Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
      Map<String, Object> variablesMap = null;
      try {
        variablesMap = execution.getVariables();
      } catch (Throwable t) {
        // In some rare cases getting the execution variables can fail (JPA entity load failure for example)
        // We ignore the exception here, because it's only meant to include variables in the initialized event.
      }
      Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
          ActivitiEventBuilder.createEntityWithVariablesEvent(ActivitiEventType.ENTITY_INITIALIZED,
              execution, variablesMap, false));
    }

    ProcessDefinitionImpl processDefinition = execution.getProcessDefinition();
    StartingExecution startingExecution = execution.getStartingExecution();
    List<ActivityImpl> initialActivityStack = processDefinition.getInitialActivityStack(startingExecution.getInitial());  
    execution.setActivity(initialActivityStack.get(0));   // 当前流程执行节点就通过execution.setActivity设置了    
    execution.performOperation(PROCESS_START_INITIAL);    //  当前操作完成之后,进行下个操作就调用execution.performOperation
  }

AtomicOperation.PROCESS_START_INITIAL里面又调用了AtomicOperation.ACTIVITY_EXECUTE,经过多次调用不同的AtomicOperation接口,完成流程实例的创建。

对于示例流程图,从开始节点到用户任务的调用AtomicOperation顺序如下:

PROCESS_START  
PROCESS_START_INITIAL  
ACTIVITY_EXECUTE  
TRANSITION_NOTIFY_LISTENER_END  
TRANSITION_DESTROY_SCOPE    
TRANSITION_NOTIFY_LISTENER_TAKE    
TRANSITION_CREATE_SCOPE    
TRANSITION_NOTIFY_LISTENER_START   
ACTIVITY_EXECUTE

2.2.4 Task节点多久持久化到数据库的

用户任务对应的ActivityImpl上绑定了UserTaskActivityBehaviorUserTaskActivityBehavior中对任务数据进行了持久化处理。

用户任务执行ACTIVITY_EXECUTE操作的时候,会触发节点上绑定的Behavior

3. 看后感

  1. 接口定义到处都是,对于后期扩展是有好处的,关键代码要找好久。
  • PVM的AtomicOperation很适合用命令模式,为什么要用委托的方式。

  • AtomicOperation的调用栈太深了。

  • CommandContext到处都是。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容

  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,777评论 2 17
  • 最近做了一次对企业/云平台级工作流引擎Activiti的调查: TA,系出名门——由JBoss公司jBPM4引擎的...
    天空之诚阅读 25,404评论 7 93
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,680评论 18 139
  • Engine解析 1. org.activiti.engine 定义了流程管理服务的接口:RepositorySe...
    西普士阅读 7,933评论 0 24
  • 静若日落日出,望眼横穿千山雪; 动若风瀑蝶舞,满耳惊容天地情。
    夕风随雨阅读 179评论 0 0