乐趣区

关于网关:如何控制工作流中的流程流转工作流流程元素之顺序流和网关的详细解析

程序流

形容
  • 程序流是连贯两个流程节点的连线
  • 流程执行完一个节点后, 会沿着节点的所有外出程序流继续执行
  • BPMN 2.0 默认的行为就是并发的: 两个外出程序流会发明两个独自的, 并发流程分支

    图形标记
  • 程序流显示为从终点到起点的箭头. 箭头总是指向起点

    XML 内容
  • 程序流须要 流程范畴内惟一的 id, 以及对 终点 起点 元素的援用

    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />

    条件程序流

    形容
  • 为程序流定义一个条件
  • 来到一个 BPMN 2.0 节点时, 默认会计算外出程序流的条件

    • 如果条件后果为 true, 就会抉择外出程序流继续执行
    • 当多条程序流被选中时, 就会创立多条分支, 流程会持续以并行形式继续执行
  • ==留神:== 不包含网关 , 网关会用特定的形式解决程序流中的条件, 这与网关类型相干

    图形标记
  • 条件程序流显示为一个失常的程序流, 在终点有一个 菱形. 条件表达式也会显示在程序流上

    XML 内容
  • 条件程序流定义为一个失常的 程序流, 蕴含 conditionExpression 子元素
  • 目前只反对tFormalExpressions, 如果没有设置xsi:type=””, 就会默认值反对目前反对的表达式类型

    <sequenceFlow id="flow" sourceRef="theStart" targetRef="theTask">
    <conditionExpression xsi:type="tFormalExpression">
      <![CDATA[${order.price > 100 && order.price < 250}]]>
    </conditionExpression>
    </sequenceFlow>
  • 以后条件表达式只能应用UEL, 应用的表达式须要返回 boolean 值, 否则会在解析表达式时抛出异样

    • 援用了流程变量的数据, 通过 getter 调用 JavaBean

      <conditionExpression xsi:type="tFormalExpression">
      <![CDATA[${order.price > 100 && order.price < 250}]]>
      </conditionExpression>
      • 通过调用办法返回一个 boolean 值

        <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${order.isStandardOrder()}]]>
        </conditionExpression>
  • 在 activiti 公布包中, 蕴含以下流程实例, 应用了值和办法表达式

    默认程序流

    形容
  • 所有的 BPMN 2.0 工作和网关都能够设置一个默认程序流
  • 只有在节点的其它外出程序流不能被选中时, 才会应用作为外出程序流继续执行
  • 默认程序流的条件设置不会失效

    图形标记
  • 默认程序流显示为 一般程序流, 终点有一个斜线标记

    XML 内容
  • 默认程序流通过对应节点的 default 属性定义
  • 上面的 XML 代码演示了排他网关设置了默认程序流 flow 2. 只有当 conditionA 和 conditionB 都返回 false 时, 才会抉择它作为外出连线继续执行:

    <exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" default="flow2" />
    <sequenceFlow id="flow1" sourceRef="exclusiveGw" targetRef="task1">
    <conditionExpression xsi:type="tFormalExpression">${conditionA}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="task2"/>
    <sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="task3">
    <conditionExpression xsi:type="tFormalExpression">${conditionB}</conditionExpression>
    </sequenceFlow>
  • 对应图形:

    网关

  • 网关用来管制流程的流向(流程的 tokens), 网关能够生产也能够生成 token
  • 网关显示成菱形图形, 外部有有一个小图标. 图标示意网关的类型:

    排他网关

    形容
  • 排他网关: 异或 XOR 网关, 用来在流程中实现 决策
  • 当流程执行到这个网关, 所有外出程序流都会被解决一遍. 其中 条件解析为 true 的程序流 (或者没有设置条件, 概念上在程序流上定义了一个[true]) 会被 选中, 让流程持续运行
  • ==留神:== 通常状况下, 所有条件后果为 true 的程序流都会被选中, 以并行形式执行, 但 排他网关只会抉择一条程序流执行. 就是说, 尽管多个程序流的条件后果为 true, 那么 XML 中的第一个程序流 (也只有这一条) 会被选中, 并用来持续运行流程. 如果没有选中任何程序流, 会抛出一个异样

    图形标记
  • 排他网关显示成一个 一般网关 (比方, 菱形图形), 外部是一个 X 图标, 示意异或(XOR) 语义.
  • 没有外部图标的网关, 默认为排他网关
  • BPMN 2.0 标准不容许在同一个流程定义中同时应用没有 X 和有 X 的菱形图形

    XML 内容
  • 用一行定义了网关, 条件表达式定义在外出程序流中
  • 模型实例:

    <exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" />
    
    <sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1">
    <conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression>
    </sequenceFlow>
    
    <sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2">
    <conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression>
    </sequenceFlow>
    
    <sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3">
    <conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression>
    </sequenceFlow>

    并行网关

    形容
  • 网关也能够示意流程中的并行状况
  • 容许将流程分成多条分支, 也能够把多条分支汇聚到一起
  • 并行网关的性能是基于进入和外出的程序流的:

    • 分支: 并行后的所有外出程序流, 为每个程序流都创立一个并发分支
    • 汇聚: 所有达到并行网关, 在此 期待 的进入分支 , 直到所有进入程序流的分支都达到当前, 流程就会通过汇聚网关
  • 同一个并行网关有多个进入和多个外出程序流, 同时具备分支和汇聚性能
  • 网关会先汇聚所有进入的程序流, 而后再切分成多个并行分支
  • 并行网关不会解析条件: 与其余网关不同, 即便程序流中定义了条件, 也会疏忽

    图形标记
  • 并行网关显示成一个一般网关 (菱形) 外部是一个 + 图标, 示意 与(AND) 语义

    XML 内容
  • 定义并行网关只须要一行 XML

    <parallelGateway id="myParallelGateway" />
  • 理论产生的行为(分支, 聚合, 同时分支聚合), 要依据并行网关的程序流来决定

     <startEvent id="theStart" />
      <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
    
      <parallelGateway id="fork" />
      <sequenceFlow sourceRef="fork" targetRef="receivePayment" />
      <sequenceFlow sourceRef="fork" targetRef="shipOrder" />
    
      <userTask id="receivePayment" name="Receive Payment" />
      <sequenceFlow sourceRef="receivePayment" targetRef="join" />
    
      <userTask id="shipOrder" name="Ship Order" />
      <sequenceFlow sourceRef="shipOrder" targetRef="join" />
    
      <parallelGateway id="join" />
      <sequenceFlow sourceRef="join" targetRef="archiveOrder" />
    
      <userTask id="archiveOrder" name="Archive Order" />
      <sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
    
      <endEvent id="theEnd" />
  • 流程启动之后, 会创立两个工作:

    ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
    TaskQuery query = taskService.createTaskQuery()
                           .processInstanceId(pi.getId())
                           .orderByTaskName()
                           .asc();
    
    List<Task> tasks = query.list();
    assertEquals(2, tasks.size());
    
    Task task1 = tasks.get(0);
    assertEquals("Receive Payment", task1.getName());
    Task task2 = tasks.get(1);
    assertEquals("Ship Order", task2.getName());

    当两个工作都实现时, 第二个并行网关会汇聚两个分支. 因为它只有一条外出连线, 不会创立并行分支, 只会创立归档订单工作

  • 留神并行网关不须要是 ” 均衡的 ”(对应并行网关的进入和外出节点数目相等). 并行网关只是 期待 所有进入程序流, 并为每个外出程序流创立并发分支, 不会受到其余流程节点的影响

    蕴含网关

    形容
  • 排他网关和并行网关的结合体:

    • 和排他网关一样, 能够在外出程序流上定义条件, 蕴含网关会解析条件
    • 和并行网关一样, 蕴含网关能够抉择多于一条程序流
  • 蕴含网关的性能是基于进入和外出程序流的:

    • 分支: 所有外出程序流的条件都会被解析, 后果为 true 的程序流会以并行形式继续执行, 会为每个程序流创立一个分支
    • 汇聚: 所有并行分支达到蕴含网关, 会进入期待状态, 直到每个蕴含流程 token 的进入程序流的分支都达到. 这是与并行网关的最大不同.蕴含网关只会期待被选中执行了的进入程序流. 在汇聚之后, 流程会穿过蕴含网关继续执行
  • 如果同一个蕴含节点领有多个进入和外出程序流, 它就会同时含有分支和汇聚性能
  • 网关会先汇聚所有领有流程 token 的进入程序流, 再依据条件判断后果为 true 的外出程序流, 为它们生成多条并行分支

    图形标记
  • 并行网关显示为一个一般网关(菱形), 外部蕴含一个圆圈图标

    XML 内容
  • 定义一个蕴含网关须要一行 XML

    <inclusiveGateway id="myInclusiveGateway" />
  • 理论的行为(分支, 汇聚, 同时分支汇聚), 是由连贯在蕴含网关的程序流决定的

     <startEvent id="theStart" />
      <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
    
      <inclusiveGateway id="fork" />
      <sequenceFlow sourceRef="fork" targetRef="receivePayment" >
      <conditionExpression xsi:type="tFormalExpression">${paymentReceived == false}</conditionExpression>
      </sequenceFlow>
      <sequenceFlow sourceRef="fork" targetRef="shipOrder" >
      <conditionExpression xsi:type="tFormalExpression">${shipOrder == true}</conditionExpression>
      </sequenceFlow>
    
      <userTask id="receivePayment" name="Receive Payment" />
      <sequenceFlow sourceRef="receivePayment" targetRef="join" />
    
      <userTask id="shipOrder" name="Ship Order" />
      <sequenceFlow sourceRef="shipOrder" targetRef="join" />
    
      <inclusiveGateway id="join" />
      <sequenceFlow sourceRef="join" targetRef="archiveOrder" />
    
      <userTask id="archiveOrder" name="Archive Order" />
      <sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
    
      <endEvent id="theEnd" />
  • 流程开始之后

    • 如果流程变量为 paymentReceived== falseshipOrder == true, 就会创立两个工作
    • 如果只有一个流程变量为 true, 就会只创立一个工作
    • 如果没有条件为 true, 就会抛出一个异样
    • 如果想防止异样, 能够定义一个默认程序流
  • 蕴含网关示例: 创立一个发货工作

    HashMap<String, Object> variableMap = new HashMap<String, Object>();
            variableMap.put("receivedPayment", true);
            variableMap.put("shipOrder", true);
            ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
    TaskQuery query = taskService.createTaskQuery()
                           .processInstanceId(pi.getId())
                           .orderByTaskName()
                           .asc();
    
    List<Task> tasks = query.list();
    assertEquals(1, tasks.size());
    
    Task task = tasks.get(0);
    assertEquals("Ship Order", task.getName());
  • 当工作实现后, 第二个蕴含网关会汇聚两个分支, 因为只有一个外出程序流, 所以不会创立并行分支, 只有归档订单工作会被激活
  • 蕴含网关不须要均衡(对应蕴含网关的进入和外出数目须要相等). 蕴含网关会期待所有进入程序流实现, 并为每个外出程序流创立并行分支, 不会受到流程中其余元素的影响

    基于事件网关

    形容
  • 基于事件网关容许依据事件判断流向

    • 网关的每个外出程序流都要连贯到一个两头捕捉事件
    • 当流程达到一个基于事件网关 , 网关会进入期待状态: 会暂停执行
    • 为每个外出程序流创立相应的事件订阅
  • 基于事件网关的外出程序流和一般程序流不同:这些程序流不会真的 ” 执行 ”, 让流程引擎去决定执行到基于事件网关的流程须要订阅哪些事件, 要思考以下条件:

    • 基于事件网关必须有两条或以上外出程序流
    • 基于事件网关后, 只能应用 intermediateCatchEvent 类型(activiti 不反对基于事件网关后连贯 ReceiveTask)
    • 连贯到基于事件网关的 intermediateCatchEvent 只能有一条进入程序流

      图形标记
  • 基于事件网关和其余 BPMN 网关一样显示成一个菱形, 外部蕴含指定图标

    XML 内容
  • 用来定义基于事件网关的 XML 元素是eventBasedGateway

    实例
  • 基于事件网关示例:

    • 当流程执行到基于事件网关时, 流程会暂停执行
    • 与此同时, 流程实例会订阅正告信号事件, 并创立一个 10 分钟后触发的定时器. 产生流程引擎为一个信号事件期待 10 分钟的成果
    • 如果 10 分钟内发出信号, 定时器就会勾销, 流程会沿着信号执行
    • 如果信号没有呈现, 流程会沿着定时器的方向后退, 信号订阅会被勾销

      <definitions id="definitions"
         xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
         xmlns:activiti="http://activiti.org/bpmn"
         targetNamespace="Examples">
      
         <signal id="alertSignal" name="alert" />
      
         <process id="catchSignal">
      
                 <startEvent id="start" />
      
                 <sequenceFlow sourceRef="start" targetRef="gw1" />
      
                 <eventBasedGateway id="gw1" />
      
                 <sequenceFlow sourceRef="gw1" targetRef="signalEvent" />
                 <sequenceFlow sourceRef="gw1" targetRef="timerEvent" />
      
                 <intermediateCatchEvent id="signalEvent" name="Alert">
                         <signalEventDefinition signalRef="alertSignal" />
                 </intermediateCatchEvent>
      
                 <intermediateCatchEvent id="timerEvent" name="Alert">
                         <timerEventDefinition>
                                 <timeDuration>PT10M</timeDuration>
                         </timerEventDefinition>
                 </intermediateCatchEvent>
      
                 <sequenceFlow sourceRef="timerEvent" targetRef="exGw1" />
                 <sequenceFlow sourceRef="signalEvent" targetRef="task" />
      
                 <userTask id="task" name="Handle alert"/>
      
                 <exclusiveGateway id="exGw1" />
      
                 <sequenceFlow sourceRef="task" targetRef="exGw1" />
                 <sequenceFlow sourceRef="exGw1" targetRef="end" />
      
                 <endEvent id="end" />
      </process>
      </definitions>
退出移动版