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);