【大白话说flowable】其他开始事件

40 阅读2分钟

1.定时开始事件(部署即闹钟,到点自动启动)

可以粗略的理解为定时任务,按照你的cron配置去发起流程。

原理:

a.部署流程定义时,引擎把 解析成 Job 插入 ACT_RU_JOB;

b.DefaultAsyncJobExecutor 每隔 500 ms 扫表;

c.当 DUEDATE_ ≤ now() 时触发 → 启动新流程实例 → 写 ACT_HI_PROCINST;

d.如果是 循环定时,引擎会重新计算下一次时间并再次写 ACT_RU_JOB。

举例:

<process id="flow_xxx" name="月度报销自动申请">
  <startEvent id="start">
    <timerEventDefinition>
        <timeCycle>0 50 23 L * ?</timeCycle>  <!-- CRON:每月最后一天 23:50 -->
    </timerEventDefinition>
  </startEvent>
  ...
  ...
  <endEvent id="end"/>
  <sequenceFlow sourceRef="genReport" targetRef="end"/>
</process>
// 暂停所有定时启动
managementService.suspendProcessDefinitionByKey("processId");
// 恢复
managementService.activateProcessDefinitionByKey("processId");
    

2.消息开始事件(点对点通知)

可以粗略的按照mq来理解,给flowable发送消息,flowable消费后启动流程。

注意: 一条消息只启动一个流程定义且必须显式调用 API才能把消息投给引擎。

<message id="msgPaySuccess" name="支付成功消息"/>   <!-- ① 声明消息 -->

  <process id="paySuccessProcess" name="支付成功后续流程">
    <!-- ② 消息开始事件 -->
    <startEvent id="start">
      <messageEventDefinition messageRef="msgPaySuccess"/>
    </startEvent>

    <!-- ③ 自动下游 -->
    
      ...
      
    <endEvent id="end"/>
    <sequenceFlow sourceRef="sendSms" targetRef="end"/>
  </process>
// ① 启动流程(消息 KEY = 模型里定义的 msgPaySuccess)
ProcessInstance inst = runtimeService.startProcessInstanceByMessage("msgPaySuccess", vars);
    
// businessKey(可选,必须唯一,用于后续关联查询)    
ProcessInstance inst = runtimeService
        .startProcessInstanceByMessage("msgPaySuccess",   // 消息 KEY
                                       dto.getOrderId(),
                                       vars);    

3.信号开始事件(广播)

可以粗劣的用mq的广播类型来理解。一旦匹配,所有订阅了该信号的流程定义(所有版本)都会被同时启动。

 <!-- ① 声明信号 -->
  <signal id="sigEmergency" name="emergencyStop" flowable:scope="global"/>
  <process id="emergencyProcess" name="紧急停机流程">
    <!-- ② 信号开始事件 -->
    <startEvent id="start">
      <signalEventDefinition signalRef="sigEmergency"/>
    </startEvent>

    <serviceTask id="shutdown" name="关闭设备"
                 flowable:delegateExpression="${shutdownDelegate}"/>
    <sequenceFlow sourceRef="start" targetRef="shutdown"/>

    <endEvent id="end"/>
  </process>
// ③ 广播:所有订阅了 "emergencyStop" 的流程定义都会被启动
//如果部署了多个版本,且都激活,所有版本都会发起流程,生成一条流程实例    
runtimeService.signalEventReceived("emergencyStop");

一句话总结: 信号事件 = 全局大喇叭 signalEventReceived("sigName") 一喊,所有订阅了该信号的 开始事件、边界事件、中间事件 同时响应; 不是“手动匹配一个流程”,而是“广播触发一批流程”。

4.条件开始事件

当放入flowable里面的某个变量发生了变化,满足了发起条件,就会发起流程。

部署后被引擎周期性轮询(默认 5 秒一次)

原理: a.部署带条件开始事件的流程定义;

b.引擎往 ACT_RU_EVENT_SUBSCRIPTION 插入一条 conditional 订阅;

c.DefaultEventDispatcher 每隔 5 秒扫表 + 执行 evaluateConditionalEvents();

d.如果当前数据库里存在全局变量(scope = execution 或 process-instance)且表达式为 true,则新建一条流程 实例;

e.表达式里可以引用任何已存在的变量,但不会因为“变量被修改”而再次启动流程(除非你把变量删了再重新插入)。

<process id="condStartProcess" name="库存补货流程">
    <!-- 条件开始事件:全局变量 inventory < 100 时启动 -->
    <startEvent id="start">
      <conditionalEventDefinition>
        <condition>${inventory < 100}</condition>   <!-- 全局变量 -->
      </conditionalEventDefinition>
    </startEvent>

    <userTask id="purchase" name="采购补货"
              flowable:assignee="${purchaseManager}"/>
    <sequenceFlow sourceRef="start" targetRef="purchase"/>
    <endEvent id="end"/>
    <sequenceFlow sourceRef="purchase" targetRef="end"/>
  </process>
// 方式 A:直接扔一个“无实例”的全局变量(最常用)
managementService.executeCommand(commandContext -> {
    CommandContextUtil.getProcessEngineConfiguration(commandContext)
                      .getVariableService()
                      .createVariable("inventory", 50, "global"); // 50 < 100
    return null;
});

// 方式 B:在任意正在运行的流程实例里 setVariable
runtimeService.setVariable(instanceId, "inventory", 50);