Flowable引擎高级特性解析:异步执行器与多租户架构
前言
Flowable作为一款强大的BPMN 2.0流程引擎,除了基础流程执行功能外,还提供了诸多高级特性。本文将深入探讨Flowable的两个核心高级特性:异步执行器架构设计与多租户实现机制,帮助开发者更好地理解和应用这些功能。
异步执行器深度解析
异步执行器架构设计
Flowable的异步执行器是其核心组件之一,负责处理定时任务和异步延续任务。理解其工作原理对于构建高性能流程应用至关重要。
任务类型与处理机制
Flowable中有两种主要任务类型:
-
定时器任务(Timer Jobs):
- 存储在ACT_RU_TIMER_JOB表中
- 包含预定的触发时间(due date)
- 专用线程定期检查并触发到期任务
- 触发后转换为异步任务
-
异步任务(Async Jobs):
- 存储在ACT_RU_JOB表中
- 执行流程实例步骤时创建
- 采用锁定机制防止重复执行
- 通过线程池执行
任务状态转换机制
任务在执行过程中会经历多种状态转换:
- 正常流程:定时器任务 → 异步任务 → 执行完成
- 异常处理:执行失败 → 定时器任务(重试) → 达到重试次数 → 死信任务(ACT_RU_DEADLETTER_JOB)
- 挂起处理:挂起的流程相关任务 → 挂起任务表(ACT_RU_SUSPENDED_JOB)
这种分离设计显著提高了查询效率,避免了旧版本中单一任务表带来的性能问题。
异步执行器配置详解
Flowable提供了丰富的配置选项来优化异步执行器性能:
线程池配置
| 参数名 | 默认值 | 说明 |
|---|---|---|
| asyncExecutorThreadPoolQueueSize | 100 | 任务执行前队列大小 |
| asyncExecutorCorePoolSize | 8 | 线程池核心线程数 |
| asyncExecutorMaxPoolSize | 8 | 线程池最大线程数 |
| asyncExecutorThreadKeepAliveTime | 5000ms | 线程空闲保持时间 |
任务获取配置
| 参数名 | 默认值 | 说明 |
|---|---|---|
| asyncExecutorMaxTimerJobsPerAcquisition | 1 | 单次获取定时任务数量 |
| asyncExecutorMaxAsyncJobsDuePerAcquisition | 1 | 单次获取异步任务数量 |
| asyncExecutorDefaultTimerJobAcquireWaitTime | 10000ms | 定时任务获取等待时间 |
| asyncExecutorDefaultAsyncJobAcquireWaitTime | 10000ms | 异步任务获取等待时间 |
高级配置
| 参数名 | 默认值 | 说明 |
|---|---|---|
| asyncExecutorNumberOfRetries | 3 | 任务重试次数 |
| asyncExecutorTimerLockTimeInMillis | 5分钟 | 定时任务锁定时间 |
| asyncExecutorAsyncJobLockTimeInMillis | 5分钟 | 异步任务锁定时间 |
| asyncExecutorResetExpiredJobsInterval | 60秒 | 过期任务检查间隔 |
最佳实践建议:在生产环境中,应根据实际负载情况调整这些参数,特别是线程池相关配置,以达到最佳性能。
BPMN解析扩展机制
Flowable提供了强大的BPMN解析扩展能力,允许开发者在解析过程中注入自定义逻辑。
解析处理器(BpmnParseHandler)机制
解析处理器分为三类:
- 预处理器(preBpmnParseHandlers):在默认处理器前执行
- 默认处理器:Flowable内置的标准处理器
- 后处理器(postBpmnParseHandlers):在默认处理器后执行
自定义解析处理器实现
实现自定义处理器有两种方式:
- 直接实现BpmnParseHandler接口:
public class CustomParseHandler implements BpmnParseHandler {
public Collection<Class> getHandledTypes() {
return Arrays.asList(Process.class, UserTask.class);
}
public void parse(BpmnParse bpmnParse, BaseElement element) {
// 自定义解析逻辑
}
}
- 继承AbstractBpmnParseHandler抽象类(推荐):
public class ProcessParseHandler extends AbstractBpmnParseHandler<Process> {
protected Class<? extends BaseElement> getHandledType() {
return Process.class;
}
protected void executeParse(BpmnParse bpmnParse, Process element) {
// 自定义解析逻辑
}
}
重要提示:自定义处理器应避免使用Flowable内部解析类,以防止兼容性问题。
高并发ID生成策略
在高并发场景下,默认的数据库块ID生成器可能成为瓶颈。Flowable提供了UUID生成器作为替代方案。
两种ID生成器对比
| 特性 | 默认ID生成器(DbIdGenerator) | UUID生成器(StrongUuidGenerator) |
|---|---|---|
| 原理 | 数据库预分配ID块 | 本地生成UUID |
| 并发能力 | 中等 | 极高 |
| 数据库依赖 | 是 | 否 |
| 配置参数 | idBlockSize | 无 |
UUID生成器配置
<bean id="processEngineConfiguration" class="...">
<property name="idGenerator">
<bean class="org.flowable.engine.impl.persistence.StrongUuidGenerator" />
</property>
</bean>
使用场景建议:只有在真正遇到高并发ID生成瓶颈时才应考虑使用UUID生成器,因为它可能带来其他性能影响。
多租户架构实现
Flowable的多租户功能允许单一引擎实例为多个租户服务,同时保持数据隔离。
多租户核心概念
- 租户标识(Tenant ID):256字符以内的唯一字符串
- 数据继承规则:
- 流程定义继承部署的租户ID
- 流程实例继承流程定义的租户ID
- 任务和执行实例继承流程实例的租户ID
多租户API使用
// 多租户部署
repositoryService.createDeployment()
.addClassPathResource("process.bpmn20.xml")
.tenantId("finance_department")
.deploy();
// 多租户信号触发
runtimeService.signalEventReceivedWithTenantId(
"paymentReceived",
null,
"finance_department");
重要注意事项
- Flowable不强制执行租户数据隔离规则,应用层需自行实现访问控制
- 租户ID只是数据的一个属性,不会自动过滤查询结果
- 对于需要严格隔离的场景,应考虑使用独立引擎实例
总结
Flowable的高级特性为复杂业务场景提供了强大支持。合理配置异步执行器可以显著提升系统性能,解析扩展机制允许深度定制流程行为,而多租户功能则为SaaS类应用提供了便利。开发者应根据实际需求选择适当的策略,并在应用层补足必要的安全控制。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



