子流程

本文中内容和案例节选自贺波老师的《深入Activiti流程引擎:核心原理与高阶实战》一书。这本书中的内容更为全面、详尽,对系统学习和深入掌握Activiti/Flowable的用法非常有帮助,推荐给大家。

QQ交流群1:633168411 已满
QQ交流群2: 582010059

参照本书录制的讲解视频地址

博客地址

当我们的业务流程非常复杂时,可以将流程拆分为一条父流程和一条或多条子流程线去执行。 当父流程进行到一部分后便开始进入子流程中流转,子流程流转完成后又回到父流程里继续执行。 子流程中经常用于分解大的业务流程。

Flowable 支持的子流程有:

  • 内嵌子流程(SubProcess)
  • 事件子流程(Event SubProcess)
  • 事务子流程(Transaction SubProcess)
  • 调用活动(callActivity)

嵌套子流程

定义

内嵌子流程又叫嵌入式子流程,它是一个可以包含其它活动、分支、事件,等的活动。我们通 常意义上说的子流程通常就是指的内嵌子流程,它表现为将一个流程(子流程)定义在另一个流程 (父流程)的内部,子流程作为父流程的一部分。子流程是主流程中的一部分流程片段,并非独立 的流程定义,一般作为局部通用逻辑处理,或者因为特定业务需要,使比较复杂的单个主流程设计 清晰直观。

图形标记

子流程显示为标准的节点,它是一个圆角矩形。子流程有两种形态:如果子流程是折叠的,就 只显示名称和一个加号标记,从而高度概括了流程,如图所示;如果子流程是展开的,子流 程的步骤显示在子流程边界内,如图所示:

  • 子流程展开展示

nest-subProcess

  • 子流程折叠展示

nest-subProcess

XML内容

子流程由 subProcess 元素定义,作为子流程一部分的所有活动,网关,事件和儿子都需要包含 在这个元素中

<process id="mainProcess" name="主流程" isExecutable="true">
<startEvent id="startEvent1"></startEvent>
 <subProcess id="subProcess">
     <startEvent id="subProcessStart" />
     
     <endEvent id="subProcessEnd" />
 </subProcess>
 </process>

可以看出,<subProcess>元素与主流程的其它元素同级,可以视作为主流程的专属属性,其本 质上只有一个流程,因此共享数据,使用主流程的 key 也能查询出子流程的任务等信息,主子流程的变量信息也是共享的。

使用示例

子流程就是将其中一部分可复用的片段组合到一个区域块中进行复用,将整个子流程都会被完 整地定义在父流程中,支持子流程的展开与缩放,使流程图设计更加简洁明了。如果不使用子流程, 同样也会将这些流程活动定义到主流程中,与子流程的效果一样,但是如果想为某部分流程活动添 加特定的事件范围,那么此时使用嵌入式子流程就很有必要。子流程主要的应用场景主要有以下两种:

1、子流程可以用于分层建模。在常见的建模工具中,都允许将子流程进行折叠来隐藏子流程的 所有细节,从而展示业务流程的高层端到端总览。

2、子流程会为事件创建新的作用域。在子流程执行中抛出的事件可以通过子流程边界上的边界 事件捕获,事件所创建的作用域只局限在子流程内。 在使用子流程时要考虑以下几个限制:

2.1、子流程有且只能有一个空开始事件,而不允许有其它类型的开始事件。

2.2、子流程至少有一个结束事件。需要注意的是,在 BPMN 2.0 规范中允许省略子流程的启动与 结束事件,但是当前 Flowable 的实现并不支持。

2.3、顺序流不能跨越子流程边界。子流程中顺序流不能直接输出流到子流程之外的活动上,有需 要可以通过边界事件替代。

下面我们用一个示例流程来演示子流程的用法。如图所示是一个贷款申请的流程,要经 过贷款申请、贷款额度审批和发放贷款三个环节,其中贷款申请环节和发放贷款环节使用的是用户 任务节点,而贷款额度审批环节使用的是子流程节点,内嵌了一个子流程。同时,子流程边界上加 入定时边界事件,如果定时器触发前子流程结束,则主流程流转到发放贷款节点;如果定时器触发 时子流程还没有结束,则直接流转到结束节点,整个流程结束。

内嵌子流程示例流程 subProcess

  <process id="nestSubProcessTest" name="子流程-嵌套子流程" isExecutable="true">
    <startEvent id="a78cb04a6b33d4993b841324220a7535a" />
    <userTask id="a0211d54ab2a949939ce31ff31c053b37" name="贷款申请">
        <extensionElements>
            <flowable:formData />
            <flowable:assigneeType>static</flowable:assigneeType>
        </extensionElements>
    </userTask>
    <sequenceFlow id="abe410f43f9f8479baddf7da69016f637" sourceRef="a78cb04a6b33d4993b841324220a7535a" targetRef="a0211d54ab2a949939ce31ff31c053b37" />
    <sequenceFlow id="Flow_0v94zzq" sourceRef="a0211d54ab2a949939ce31ff31c053b37" targetRef="Activity_1ndamrq" />
    <subProcess id="Activity_1ndamrq" name="贷款额度审批">
        <startEvent id="Event_1xr63oz">
            <extensionElements>
                <flowable:formData />
            </extensionElements>
        </startEvent>
        <sequenceFlow id="Flow_1onxxsx" sourceRef="Event_1xr63oz" targetRef="Activity_0zp1e7g" />
        <userTask id="Activity_10gcslh" name="复核贷款额度">
            <extensionElements>
                <flowable:formData />
                <flowable:assigneeType>static</flowable:assigneeType>
            </extensionElements>
        </userTask>
        <endEvent id="Event_0ulgoqy" />
        <sequenceFlow id="Flow_0pcmaok" sourceRef="Activity_10gcslh" targetRef="Event_0ulgoqy" />
        <userTask id="Activity_0zp1e7g" name="审批贷款额度">
            <extensionElements>
                <flowable:assigneeType>static</flowable:assigneeType>
                <flowable:formData />
            </extensionElements>
        </userTask>
        <exclusiveGateway id="Gateway_1h3mxrw" default="Flow_0jcc7nk" />
        <sequenceFlow id="Flow_1j4me9j" sourceRef="Activity_0zp1e7g" targetRef="Gateway_1h3mxrw" />
        <sequenceFlow id="Flow_0jcc7nk" name="小于100w" sourceRef="Gateway_1h3mxrw" targetRef="Event_0ulgoqy" />
        <sequenceFlow id="Flow_06jy5zt" name="大于等于100w" sourceRef="Gateway_1h3mxrw" targetRef="Activity_10gcslh">
            <conditionExpression xsi:type="tFormalExpression">${money&gt;=100}</conditionExpression>
        </sequenceFlow>
    </subProcess>
    <endEvent id="Event_1e8x10z" />
    <userTask id="Activity_0id07bt" name="发放贷款">
        <extensionElements>
            <flowable:formData />
            <flowable:assigneeType>static</flowable:assigneeType>
        </extensionElements>
    </userTask>
    <sequenceFlow id="Flow_1h37g0l" sourceRef="Activity_1ndamrq" targetRef="Activity_0id07bt" />
    <sequenceFlow id="Flow_1b7pjk9" sourceRef="Activity_0id07bt" targetRef="Event_1e8x10z" />
    <boundaryEvent id="Event_1902kar" name="30分钟" attachedToRef="Activity_1ndamrq">
        <timerEventDefinition>
            <timeDuration>PT2M</timeDuration>
        </timerEventDefinition>
    </boundaryEvent>
    <sequenceFlow id="Flow_1ap39px" sourceRef="Event_1902kar" targetRef="Event_1e8x10z" />
</process>

演示demo

嵌套子流程

事件子流程

定义

事件子流程是 BPMN 2.0 中加入的新元素,它是指通过事件触发的子流程,可以存在于在流程 级别,或者任何子流程级别。和内嵌子流程类似,把一系列的活动归结到一起处理,不同之处在于 事件子流程不能直接启动,要被动地由其它的事件触发启动。事件子流程可以通过消息事件、错误 事件、信号事件、定时器事件或补偿事件等触发。

图形标记

事件子流程可以显示为边框为虚线的内嵌子流程,如图所示:

subprocess

XML内容

事件子流程的 XML 内容与内嵌子流程是一样的,不同之处在于事件子流程需要把 triggeredByEvent 属性设置为 true:

<process id="mainProcess" name="主流程" isExecutable="true">
    <startEvent id="startEvent1"></startEvent>
     <subProcess id="subProcess" name="事件子流程" triggeredByEvent="true">
         <startEvent id="subProcessStart" />
         <endEvent id="subProcessEnd" />
     </subProcess>
 </process>

使用示例

用于触发事件子流程的事件,使用开始事件进行配置。因此可知,不能在事件子流程中使用空 启动事件,Flowable 支持的事件子流程中必须以错误开始事件或者消息开始事件开始。开始事件的 订阅在包含事件子流程的作用域(流程实例或子流程)创建时就会创建,当作用域销毁也会删除订 阅。事件子流程里面需要有结束节点。 事件子流程可以配置为中断或不中断的,中断的子流程会取消当前作用域内的所有执行,而非中 断的事件子流程将创建一个新的并行执行。中断事件子流程只会被作用域范围内的活动触发一次, 而非中断事件子流程可以多次触发。子流程是否是中断的,通过触发事件子流程的开始事件配置。 注意,Flowable 只支持中断事件子流程。 事件子流程不能有任何入口或出口顺序流。因为事件子流程是由事件触发的,入口顺序流是没 有意义的;当事件子流程结束时,要么当前作用域已经结束了(中断事件子流程的情况),要么是非中 断子流程创建的并行执行结束。 (一)事件子流程处于“流程级别” 如图所示是使用错误开始事件触发事件子流程的例子,主流程是一个扩容流程,用户申 请扩容后,由客服进行扩容操作,如果扩容成功,流程正常结束;如果扩容失败,流程异常结束, 抛出错误信号。事件子流程捕获到错误信号触发,由管理员进行扩容操作,该事件子流程处于“流 程级别”,即流程实例的范围。

事件子流程处于流程级别示例

XML文件内容

<error id="errorStart" errorCode="501" />
  <process id="EventSubProcess" name="子流程-事件子流程" isExecutable="true">
    <startEvent id="a176c794d61404eecad5499bef1ad0827" />
    <userTask id="acb02ce20ac3e4a759349bc6a27b83edf" name="报销申请">
      <extensionElements>
        <flowable:formData />
        <flowable:assigneeType>static</flowable:assigneeType>
      </extensionElements>
    </userTask>
    <sequenceFlow id="a3cf9d622e7f244e593daa3de4ea5cd28" sourceRef="a176c794d61404eecad5499bef1ad0827" targetRef="acb02ce20ac3e4a759349bc6a27b83edf" />
    <exclusiveGateway id="Gateway_01ldt0g" default="Flow_1qlsjb2" />
    <sequenceFlow id="Flow_0if2u86" sourceRef="acb02ce20ac3e4a759349bc6a27b83edf" targetRef="Gateway_01ldt0g" />
    <endEvent id="Event_0h4opqw" />
    <sequenceFlow id="Flow_1qlsjb2" sourceRef="Gateway_01ldt0g" targetRef="Event_0h4opqw" />
    <sequenceFlow id="Flow_125nv4v" name="部门预算不够" sourceRef="Gateway_01ldt0g" targetRef="Event_1vmolrd">
      <conditionExpression xsi:type="tFormalExpression">${flag == false}</conditionExpression>
    </sequenceFlow>
    <subProcess id="Activity_093jvyy" name="制定部门预算子流程" triggeredByEvent="true">
      <userTask id="Activity_0imaet9" name="重新制定部门预算">
        <extensionElements>
          <flowable:formData />
          <flowable:assigneeType>static</flowable:assigneeType>
        </extensionElements>
      </userTask>
      <sequenceFlow id="Flow_031n3ls" sourceRef="Event_1czfv34" targetRef="Activity_0imaet9" />
      <endEvent id="Event_1rizm83" />
      <sequenceFlow id="Flow_0ljilul" sourceRef="Activity_0imaet9" targetRef="Event_1rizm83" />
      <startEvent id="Event_1czfv34">
        <extensionElements>
          <flowable:formData />
        </extensionElements>
        <errorEventDefinition errorRef="errorStart" flowable:errorVariableLocalScope="false" flowable:errorVariableTransient="false" />
      </startEvent>
    </subProcess>
    <endEvent id="Event_1vmolrd">
      <errorEventDefinition errorRef="errorStart" flowable:errorVariableLocalScope="false" flowable:errorVariableTransient="false" />
    </endEvent>
  </process>

演示demo

事件子流程

事务子流程

定义

事务子流程也称作事务块,是一个嵌入式子流程,用来处理一组必须在同一个事务中完成的活 动,使它们共同成功或失败。事务子流程中如果有一个活动失败或者取消,整个事务子流程的所有 活动回滚,可以有三种不同的结果:

  1. 事务成功,如果没有取消也没有因为异常终止。如果事务子流程是成功的,就会使用外出顺 序流继续执行。如果流程后来抛出了一个补偿事件,成功的事务可能被补偿。需要注意的是,和普 通内嵌子流程一样,事务可能在成功后,使用中间补偿事件进行补偿。
  2. 事务取消,如果流程到达取消结束事件。在这种情况下,所有的执行都被终止并被删除,然 后剩余的一个执行被设置为取消边界事件,这会触发补偿。在补偿完成之后,事务子流程会使用取 消边界事务的外出顺序流向下执行。
  3. 如果一个错误事件被抛出,而且没有在事务子流程中捕获,事务将异常结束。如果在事务子 流程的边界上捕获错误,也适用于这种情况。在这些情况下,不会执行赔偿。

图形标记

事务子流程显示为内嵌子流程,使用双线边框,如图所示:

subprocess

XML内容

事务子流程由 transaction 元素定义,作为子流程一部分的所有活动,网关,事件都需要 包含在这个元素中:

<process id="mainProcess" name=" " isExecutable="true">
     <startEvent id="startEvent1"></startEvent>
     <transaction id="myTransaction" >
         <startEvent id="subProcessStart" />
         <endEvent id="subProcessEnd" />
     </transaction>
 </process>

使用示例

BPMN 的事务与数据库 ACID 事务有相似之处,但它们是两个不同的概念,两者的不同之处在 于:

⑴ACID 事务一般持续时间很短,但 BPMN 事务可能持续较长时间(几小时,几天,甚至更长 时间),可以试想这样的场景:一个事务分组中包含的节点有用户任务,通常人们的响应时间会比 较长,或者在一些情况下,BPMN 事务可能会等待某个事务事件发生才往下执行。这样的操作通常 要比在数据库中更新记录或使用事务队列存储消息花费更长的时间。

⑵BPMN 事务一般要跨越多个 ACID 事务,因为通常不能在整个业务节点的过程中保持 ACID 的事务。当 BPMN 事务处理涉及多个 ACID 事务时,会失去 ACID 的特性。比如事务子流程中两 个相邻的服务节点均调用外部服务,前一个完成了,第二个还没完成时,对外部来说,前一个服务 调用成功这个中间状态外部是能感知到的,意味着实现 BPMN 事务时放弃了隔离属性。

⑶BPMN 事务不能使用通常的方式回滚。由于 BPMN 事务可横跨多个 ACID 事务,在 BPMN 事务取消时一些 ACID 事务可能已经提交了,这种情况下就不能被回滚了。 由于 BPMN 事务通常是需要长时间运行的,所以缺乏隔离和回滚机制需要以不同的方式处理。 在实践中,通常没有更好的解决方案,而是以特定于领域的方式处理这些问题:

⑴使用补偿执行回滚。如果在事务范围内引发取消事件,则所有成功执行并具有补偿处理程序 的活动将执行补偿。

⑵隔离性的缺乏通常使用特定领域的解决方法来解决。举个例子,比如相邻的客房预订和费用 支付两个环节都是调用的第三方服务,在确定第一个客户可以付款之前,酒店房间可能会被预订给 第二个客户。由于从商业角度来看这可能是不可取的,预订服务可能会选择允许超额预订。另外, BPMN 事务可能因某些原因被中断,预定服务必须处理这种情况,比如客户已经预定了旅店,但是 一直没有付款。针对这种情况,预定服务需要设定一个策略,如果客房预订超过最大允许时间后还 没有付款,就取消预订。

综上所述,虽然 ACID 事务为常规问题(回滚,隔离级别和启发式结果)提供了一个通用的解 决方案,但在实现 BPMN 事务时,我们还需要为这些问题找到针对特定领域的解决方案。 BPMN 事务可以保证一致性,即所有活动都能够成功执行,或者某些活动无法执行时所有已执 行成功活动进行补偿。无论哪种情况,最终都处于一致的状态。但是,需要注意的是,在 Flowable 中,BPMN 事务的一致性模型建立在流程执行的一致性模型之上。Flowable 执行流程是 ACID 事务 性的,并使用乐观锁解决并发的问题。在 Flowable 中,BPMN 的错误、取消和补偿事件同样都建立 在 ACID 事务和乐观锁之上。比如,当两个并发执行达到取消结束事件时,可能会触发两次补偿, 最终因为乐观锁冲突失败。

下面我们看一个使用事务子流程的示例,如图所示,用户提交订单后,进入订单支付事 务子流程,顺利完成订单支付需要经过锁定库存、用户支付订单和扣减库存环节,如果用户取消订 单、30 分钟未支付订单或扣减库存失败,都会使子流程到达取消结束事件并执行释放库存和费用 退回补偿,被事务子流程上的取消边界事件捕获后结束子流程,接下来流转到自动取消订单服务。

事务子流程示例流程

subprocess

XML内容

<error id="errorFlag" errorCode="500" />
  <process id="ThransactionSubProcessTest" name="子流程-事务子流程" isExecutable="true">
    <startEvent id="a1bc9933739624c6694151aff2dce872b" />
    <userTask id="aa49686c18f1c48879976ba75a55fcbc6" name="用户提交订单">
      <extensionElements>
        <flowable:formData />
        <flowable:assigneeType>static</flowable:assigneeType>
      </extensionElements>
    </userTask>
    <sequenceFlow id="ab3c3111802e74e1c829879ce06ef62f1" sourceRef="a1bc9933739624c6694151aff2dce872b" targetRef="aa49686c18f1c48879976ba75a55fcbc6" />
    <transaction id="Activity_1vnyjkd" name="事务子流程">
      <startEvent id="Event_12nf6w8">
        <extensionElements>
          <flowable:formData />
        </extensionElements>
      </startEvent>
      <sequenceFlow id="Flow_1qdwcnq" sourceRef="Event_12nf6w8" targetRef="Gateway_1swfvxl" />
      <parallelGateway id="Gateway_1swfvxl" />
      <sequenceFlow id="Flow_17rtq7v" sourceRef="Gateway_1swfvxl" targetRef="Activity_1gw2yen" />
      <serviceTask id="Activity_1gw2yen" name="锁定库存" flowable:class="com.dragon.test.bpmn.delegate.TreasuryLockService">
        <extensionElements>
          <flowable:formData />
          <flowable:assigneeType>static</flowable:assigneeType>
        </extensionElements>
      </serviceTask>
      <userTask id="Activity_0s32nn4" name="用户取消订单">
        <extensionElements>
          <flowable:formData />
          <flowable:assigneeType>static</flowable:assigneeType>
        </extensionElements>
      </userTask>
      <sequenceFlow id="Flow_0x4x7li" sourceRef="Gateway_1swfvxl" targetRef="Activity_0s32nn4" />
      <userTask id="Activity_0k0ojol" name="用户支付订单">
        <extensionElements>
          <flowable:formData />
          <flowable:assigneeType>static</flowable:assigneeType>
        </extensionElements>
      </userTask>
      <sequenceFlow id="Flow_107046y" sourceRef="Activity_1gw2yen" targetRef="Activity_0k0ojol" />
      <sequenceFlow id="Flow_1yuazgn" sourceRef="Activity_0k0ojol" targetRef="Activity_0bi67sc" />
      <serviceTask id="Activity_0bi67sc" name="扣减库存" flowable:class="com.dragon.test.bpmn.delegate.TreasuryDeductService">
        <extensionElements>
          <flowable:assigneeType>static</flowable:assigneeType>
          <flowable:formData />
        </extensionElements>
      </serviceTask>
      <endEvent id="Event_167temk" />
      <sequenceFlow id="Flow_0pkp6lj" sourceRef="Activity_0bi67sc" targetRef="Event_167temk" />
      <sequenceFlow id="Flow_12q7c71" sourceRef="Activity_0s32nn4" targetRef="Event_1mt0jp2" />
      <endEvent id="Event_1mt0jp2">
        <cancelEventDefinition />
      </endEvent>
      <boundaryEvent id="Event_1w62z13" attachedToRef="Activity_0bi67sc">
        <errorEventDefinition errorRef="errorFlag" flowable:errorVariableLocalScope="false" flowable:errorVariableTransient="false" />
      </boundaryEvent>
      <sequenceFlow id="Flow_03od54n" sourceRef="Event_1w62z13" targetRef="Event_1mt0jp2" />
      <boundaryEvent id="Event_0fblty6" name="30分钟" attachedToRef="Activity_0k0ojol">
        <timerEventDefinition>
          <timeDuration>PT3M</timeDuration>
        </timerEventDefinition>
      </boundaryEvent>
      <sequenceFlow id="Flow_0hmzy4u" sourceRef="Event_0fblty6" targetRef="Event_1mt0jp2" />
      <boundaryEvent id="Event_0dzq6vl" attachedToRef="Activity_1gw2yen">
        <compensateEventDefinition />
      </boundaryEvent>
      <serviceTask id="Activity_15oy2bt" name="释放库存" isForCompensation="true" flowable:class="com.dragon.test.bpmn.delegate.TreasuryReleaseService" />
      <boundaryEvent id="Event_0rv7u1v" attachedToRef="Activity_0k0ojol">
        <compensateEventDefinition />
      </boundaryEvent>
      <serviceTask id="Activity_0gw5xlk" name="费用退回" isForCompensation="true" flowable:class="com.dragon.test.bpmn.delegate.RefundPaymentService" />
      <association id="Association_1a1b669" associationDirection="One" sourceRef="Event_0dzq6vl" targetRef="Activity_15oy2bt" />
      <association id="Association_0vig570" associationDirection="One" sourceRef="Event_0rv7u1v" targetRef="Activity_0gw5xlk" />
    </transaction>
    <sequenceFlow id="Flow_0ynhbof" sourceRef="aa49686c18f1c48879976ba75a55fcbc6" targetRef="Activity_1vnyjkd" />
    <boundaryEvent id="Event_0lxd35r" attachedToRef="Activity_1vnyjkd">
      <cancelEventDefinition />
    </boundaryEvent>
    <sequenceFlow id="Flow_0p83e5j" sourceRef="Event_0lxd35r" targetRef="Activity_0xmvtli" />
    <serviceTask id="Activity_0xmvtli" name="自动取消订单" flowable:class="com.dragon.test.bpmn.delegate.CancelOrderService">
      <extensionElements>
        <flowable:formData />
        <flowable:assigneeType>static</flowable:assigneeType>
      </extensionElements>
    </serviceTask>
    <endEvent id="Event_0h8me6c" />
    <sequenceFlow id="Flow_1vvt0is" sourceRef="Activity_0xmvtli" targetRef="Event_0h8me6c" />
    <endEvent id="Event_1954lc4" />
    <sequenceFlow id="Flow_0kcxljy" sourceRef="Activity_1vnyjkd" targetRef="Event_1954lc4" />
  </process>

演示demo

事务子流程

调用活动

定义

调用活动是在一个流程定义中调用另一个独立的流程定义,通常可以定义一些通用的流程作为 这种调用子流程,供其他多个流程定义复用。这种子流程使用 callActivity 元素来进行调用,很方 便地嵌入到主流程中,用起来比较方便。

图形标记

调用活动显示为标准的节点,它是一个圆角矩形,不过是粗边框,如图所示。

callactivity

XML内容

调用活动的 XML 定义如下:

<callActivity id="Activity_1q7t28e" name="贷款额度审批" calledElement="ApproveLoanSubProcess" flowable:inheritVariables="true" flowable:processInstanceName="贷款额度审批" flowable:calledElementType="key">
    <extensionElements>
        <flowable:assigneeType>static</flowable:assigneeType>
        <flowable:formData />
        <flowable:modelBpmnExtension>[{"id":"8c7aefbf087f4d680fc36b871d77c967","modelId":"1252465dd6e511eda69100ff2cb2ed0e","modelKey":"ApproveLoanSubProcess","name":"贷款额度审批","appSn":"businessFlow","appName":"财务流程","categoryCode":"zshjt","categoryName":"中石化集团","status":3,"statusName":"已发布"}]</flowable:modelBpmnExtension>
    </extensionElements>
</callActivity>

调用活动是一个普通活动,需要通过 calledElement 属性引用被调用的外部流程定义的 key。调 用活动可以向子流程传递与接收流程变量:①使用 flowable:in 标签定义父流程变量传入到子流程流 程变量的映射,在子流程启动时复制到子流程;②使用用 flowable:out 标签定义子流程变量回传到父 流程变量的映射,在其结束时复制回主流程。调用活动的拓展属性如表所示:

属性名称属性说明示例
calledElement被调用流程的 key,对应的流程定义应独立存在<callActivity calledElement="testProcessDefinitonKey">
businessKey子流程的 businessKey,可以使用表达式<callActivity flowable:businessKey="subProcessBusinessKey">
inheritBusinessKey值为 true 时子流程复用父流程的 businessKey,该属性在businessKey 属性没有配置时才生效<callActivity flowable:inheritVariables="true">
inheritVariables值为 true 时将父流程所有流程变量传递给子流程<callActivity flowable:inheritVariables="true">
flowable:in将父流程的流程变量传入子流程(父流程变量必须事先定义,否则将不能获取)<flowable:in source="someVariableInMainProcess" target="nameOfVariableInSubProcess"></flowable:in>,source:主流程中的变量名称,可以使用表达式;target:在将主流程变量传递给子流程中变量的名称,一般和 sourse 同名避免错误的出现
flowable:out调用活动执行完成后的结果<flowable:out source="someVariableInSubProcss"target="nameOfVariableInMainProcess"></flowable:out>,source:子流程中的变量名称,可以使用表达式;target:在将子流程变量传递给父流程中变量的名称,一般和 source 同名避免错误的出现

由于主子流程是不同的实例,因此无法通过主流程的 key 查询子流程的任务,在查询子任务时需要使用子流程的 key 来进行查询。

界面操作

使用示例

子流程设计

子流程如图所示,子流程发起后首先进入“审批贷款额度”用户任务节点,审批完成后 由分支网关进行分支决策:贷款额度小于 100w 流程直接结束;贷款额度大于 100w 进入“复核贷 款额度”用户任务节点,审批完成后流程结束。

callactivity

子流程的XML内容

<process id="ApproveLoanSubProcess" name="子流程-调用活动-审批贷款子流程" isExecutable="true">
    <startEvent id="ab7ef4cb0c5e6455ab4406613fb6b198f" />
    <userTask id="a43f40e7a7d60446585661ed8b2232732" name="审批贷款额度">
      <extensionElements>
        <flowable:formData />
        <flowable:assigneeType>static</flowable:assigneeType>
      </extensionElements>
    </userTask>
    <sequenceFlow id="a75d9acf085184bc5b49fcbb29a7768e9" sourceRef="ab7ef4cb0c5e6455ab4406613fb6b198f" targetRef="a43f40e7a7d60446585661ed8b2232732" />
    <exclusiveGateway id="Gateway_09287wv" default="Flow_0nh3xov" />
    <sequenceFlow id="Flow_1yaqka8" sourceRef="a43f40e7a7d60446585661ed8b2232732" targetRef="Gateway_09287wv" />
    <userTask id="Activity_1pxhie8" name="复核贷款额度">
      <extensionElements>
        <flowable:formData />
        <flowable:assigneeType>static</flowable:assigneeType>
      </extensionElements>
    </userTask>
    <sequenceFlow id="Flow_0nh3xov" name="额度&#62;100万元" sourceRef="Gateway_09287wv" targetRef="Activity_1pxhie8" />
    <endEvent id="Event_1cgk4gr" />
    <sequenceFlow id="Flow_1wdrb0h" name="额度&#60;=100万元" sourceRef="Gateway_09287wv" targetRef="Event_1cgk4gr">
      <conditionExpression xsi:type="tFormalExpression">${loanAmount&lt;=1000000}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="Flow_1c8sxxy" sourceRef="Activity_1pxhie8" targetRef="Event_1cgk4gr" />
  </process>

主流程设计

主流程如图所示,主流程发起后进入“贷款申请”用户任务节点,提交后进入“贷款额 度审批”调用活动节点,父流程进入等待状态,启动并执行上述子流程,子流程结束后父流程继续 执行,进入“发放贷款”用户任务节点,办理完成后流程结束。

callactivity

主流程的XML内容

<process id="CallActivitySubprocessTest" name="子流程-调用活动" isExecutable="true">
    <startEvent id="a3d0c6c7163c5499cb41510c83ba21645" />
    <userTask id="a8c6f47b1424b4115ba9f66434f10529e" name="贷款申请">
      <extensionElements>
        <flowable:formData />
        <flowable:assigneeType>static</flowable:assigneeType>
      </extensionElements>
    </userTask>
    <sequenceFlow id="a9b2a0637bfa449e29959c2b21d476125" sourceRef="a3d0c6c7163c5499cb41510c83ba21645" targetRef="a8c6f47b1424b4115ba9f66434f10529e" />
    <sequenceFlow id="Flow_14yhbzw" sourceRef="a8c6f47b1424b4115ba9f66434f10529e" targetRef="Activity_1q7t28e" />
    <callActivity id="Activity_1q7t28e" name="贷款额度审批" calledElement="ApproveLoanSubProcess" flowable:inheritVariables="true" flowable:processInstanceName="贷款额度审批" flowable:calledElementType="key">
      <extensionElements>
        <flowable:assigneeType>static</flowable:assigneeType>
        <flowable:formData />
        <flowable:modelBpmnExtension>[{"id":"8c7aefbf087f4d680fc36b871d77c967","modelId":"1252465dd6e511eda69100ff2cb2ed0e","modelKey":"ApproveLoanSubProcess","name":"贷款额度审批","appSn":"businessFlow","appName":"财务流程","categoryCode":"zshjt","categoryName":"中石化集团","status":3,"statusName":"已发布"}]</flowable:modelBpmnExtension>
      </extensionElements>
    </callActivity>
    <endEvent id="Event_16u42q4" />
    <userTask id="Activity_0olujzk" name="发放贷款">
      <extensionElements>
        <flowable:formData />
        <flowable:assigneeType>static</flowable:assigneeType>
      </extensionElements>
    </userTask>
    <sequenceFlow id="Flow_1dqsl2g" sourceRef="Activity_1q7t28e" targetRef="Activity_0olujzk" />
    <sequenceFlow id="Flow_0n0kqrn" sourceRef="Activity_0olujzk" targetRef="Event_16u42q4" />
  </process>

演示demo

调用活动-主流程

调用活动-子流程

特殊子流程

敬请期待