简介:Activiti 6社区版中文用户指南,面向Java开发人员、流程建模师及企业应用集成工程师,帮助读者理解工作流引擎的部署、配置与二次开发。指南系统覆盖Activiti 6.0核心知识,包含环境准备、ProcessEngine配置、数据库及JNDI数据源设置、Job Executor、邮件服务器配置、Spring/Spring Boot集成、BAR部署、流程版本控制,以及BPMN 2.0标准中各类事件、网关、任务等完整构造说明。资源为1个独立docx文档,约4.22MB,已有1816位学习者下载阅读。读者可从中掌握快速入门步骤、Activiti API服务调用、单元测试方法、表达式与脚本应用,以及计时器事件、信号事件、边界事件等关键BPMN元素的实际用法,是系统学习工作流技术栈的实用参考资料。
1. 拿到这份 Activiti 6 中文 用户指南 docx,第一件事不是急着翻正文
很多刚接手流程引擎的同事,第一眼看到这个标题都会愣一下:一份 docx 格式的 Activiti 6 中文用户指南,到底能解决什么问题?它不是源码包,也不是某个项目的二次开发文档,而是一份把“引擎搭建、表结构、部署方式、任务流转、配置调优”串在一起的离线知识库。对正在评估 Activiti 6 能不能接进现有系统的人来说,这份指南的价值在于提前画出了边界:哪些事情引擎帮你做了,哪些事情必须自己写代码。你看完第一章基本能判断这个项目要不要引入;看到第三章就能照着配置出一个能跑的最小引擎;后面几张表和数据字典,则是你真正部署到测试环境时反复翻的参考手册。
2. 先搞清引擎骨架:从 docx 目录里拆出表结构、服务与配置
Activiti 6 是一个基于 BPMN 2.0 标准的工作流引擎,核心思路是“流程定义与业务代码分离”。文档开头往往花很大篇幅讲 BPMN 概念,很多人看着看着就困了。我的建议是反过来读:先弄清引擎启动后数据库里会发生什么,再回来看流程模型。这一章带你按“目录优先”的方式把这份中文用户指南拆成三块可操作的内容,让你在写代码之前,先知道自己在跟什么打交道。
2.1 用户指南的正确读法:一类一章,跳过暂时用不上的
一份常见的中文 Activiti 6 用户指南,大致会按下面这样的章节结构组织。你不需要从头到尾逐字读,而是按照项目阶段找对应章节。
| 文档章节 | 作用 | 什么时候读 |
|---|---|---|
| 安装与配置 | 环境要求、数据库配置、引擎初始化 | 搭环境当天必须读 |
| 引擎架构与流程虚拟机 | 流程如何被解析、执行 | 理解原理时读一遍 |
| BPMN 2.0 模型元素 | 用户任务、排他网关、子流程、事件定义 | 画流程图前查阅 |
| 五个核心服务接口 | Repository、Runtime、Task、History、Identity | 动手写代码前通读 |
| 任务处理与操作 | 签收、委派、转办、催办 | 开发任务审批功能时精读 |
| 流程实例与执行管理 | 挂起、终止、变量作用域 | 做流程控制功能时精读 |
| 监听器与扩展点 | 任务监听器、执行监听器、Spring 集成 | 需要扩展业务时精读 |
| 引擎配置参数 | 数据库策略、历史级别、异步执行器 | 部署前逐个对照 |
| 表格清单与数据字典 | ACT_GE、ACT_RE、ACT_RU、ACT_HI | 排查问题随时翻 |
我个人习惯是:第一天只读“安装与配置”和“引擎架构”两部分,然后立刻动手跑通一个流程;之后写什么功能,再回头查对应章节。文档不是小说,你看完不敲一行命令,三天后肯定忘干净。
2.2 引擎启动时的骨架:ProcessEngine 和它的服务是怎么被拼起来的
Activiti 6 里一切动作都围绕一个核心对象展开:ProcessEngine。它是引擎的门面,内部由ProcessEngineConfiguration负责组装数据源、事务管理器、历史级别、命令拦截器等。你调用ProcessEngines.getDefaultProcessEngine()时,引擎会去activiti.cfg.xml或 Spring 配置里读取参数,然后初始化七张分类下的数据表。
常见做法是:自己显式构建ProcessEngineConfiguration,而不是完全依赖默认配置。原因很简单,实际项目里数据源一定是你自己配的,事务管理器也要跟 Spring 的事务边界对齐。引擎本身是“命令模式”设计,你调用某个 Service 方法时,其实是往命令执行器里塞了一个命令,由拦截器链统一处理事务和日志。理解这一点对后面排查“为什么数据没提交”“为什么 SQL 没执行”非常有帮助。
// 显式构建引擎配置,使用本地 MySQL ProcessEngineConfiguration config = ProcessEngineConfiguration .createStandaloneProcessEngineConfiguration() .setJdbcUrl("jdbc:mysql://localhost:3306/activiti_test?useUnicode=true&characterEncoding=utf8") .setJdbcUsername("root") .setJdbcPassword("123456") .setDatabaseSchemaUpdate("true") .setHistoryLevel(HistoryLevel.FULL.getLevel()); ProcessEngine processEngine = config.buildProcessEngine();这段代码把数据库连接和初始化策略都写死了,databaseSchemaUpdate设为 true,引擎启动时会自动检查并创建缺失的业务表,适合开发阶段。生产环境我建议改为false,由专门的脚本管理表结构变更。historyLevel决定历史数据记录到多细,业务上有审计需求就设 FULL,否则设 AUDIT 可以减少很多冗余数据。
2.3 7 张基础表与五个核心服务:文档里最值得反复看的清单
Activiti 6 的数据表按前缀分了四类,搞清它们你就掌握了引擎的存储逻辑。ACT_RE_是流程定义和模型等静态资源;ACT_RU_是运行中的流程实例、任务、变量等临时数据,流程结束后会被清掉;ACT_HI_是所有历史数据,相当于流程的档案;ACT_GE_存放通用数据,比如流程图的二进制内容。
| 表名前缀 | 典型表 | 存什么 | 生命周期 |
|---|---|---|---|
| ACT_RE_ | ACT_RE_PROCDEF、ACT_RE_DEPLOYMENT | 流程定义与部署包 | 长期保存 |
| ACT_RU_ | ACT_RU_TASK、ACT_RU_EXECUTION、ACT_RU_VARIABLE | 运行中任务和执行流 | 实例结束即清理 |
| ACT_HI_ | ACT_HI_PROCINST、ACT_HI_TASKINST、ACT_HI_ACTINST | 历史实例、任务、活动节点 | 一直保留 |
| ACT_GE_ | ACT_GE_BYTEARRAY、ACT_GE_PROPERTY | 流程图文件、引擎属性 | 长期保存 |
| ACT_ID_ | ACT_ID_USER、ACT_ID_GROUP | 身份信息 | 不用可跳过 |
核心服务里,你最先接触的通常是这三个:RepositoryService负责流程定义和部署包的增删改查;RuntimeService负责启动流程实例和设置流程变量;TaskService负责查询、认领、审批用户任务。其余如HistoryService查历史数据,ManagementService做引擎管理,按需学习即可。记住这张表,后面文档里所有配置参数才不会显得无厘头。
3. 照着指南搭的第一个可跑引擎:依赖、部署与任务闭环
理论看再多,不如亲手把引擎跑起来。这一章我们从零搭一个最小可运行环境,中间会踩到不少坑,包括依赖版本冲突、流程文件放错目录、部署成功但查询不到任务等。我把常见做法展开写,你照着操作,大概半小时就能看到第一个流程实例落地。
3.1 最小 Maven 依赖:用最小集合跑通
Activiti 6 的工程依赖比 5.x 清爽一些,但如果你直接搜“activiti 依赖”很容易被网上各种组合带偏。最常见做法是引入activiti-engine,再用 H2 或 MySQL 作为数据源。下面是适合本地调试的依赖组合。
<dependency> <groupId>org.activiti</groupId> <artifactId>activiti-engine</artifactId> <version>6.0.0</version> </dependency> <!-- 本地调试用内存数据库,打包时排除 --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.200</version> <scope>runtime</scope> </dependency> <!-- 与 Spring 集成时才需要 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring</artifactId> <version>6.0.0</version> </dependency>activiti-engine是引擎本体,里面包含了 BPMN 解析、流程虚拟机、命令执行器等核心模块。activiti-spring负责把引擎对象交给 Spring 管理,没有它你也能跑,但事务边界和对 Bean 的注入就得自己处理,后面会很痛苦。H2 的scope设为 runtime,意味着编译期不引用,只在运行时提供驱动,这是为了避免在业务代码里直接依赖某个数据库。
3.2 部署一条 BPMN 流程:流程定义、部署包和流程实例的关系
很多新手容易把“部署流程”和“启动流程”混在一起。部署,是把一个.bpmn20.xml流程文件交给引擎保存,相当于注册了流程的类型;启动,才是真正创建一个执行实例。流程文件放在src/main/resources/processes/下,下面是部署代码。
// 部署一条请假流程 RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deployment = repositoryService.createDeployment() .addClasspathResource("processes/leave.bpmn20.xml") .name("请假流程") .deploy(); System.out.println("部署 ID:" + deployment.getId());部署完成后,引擎会解析 XML 里的 BPMN 元素,校验网关、事件、任务节点是否合法。addClasspathResource是从 classpath 加载文件,路径必须是processes/下的相对路径;如果你用addInputStream,则文件放哪都行。这里有个关键点:同样一条流程可以重复部署,每次部署会产生一个新的流程定义版本,业务流程还在等待旧版本,但新审批会使用新版本,这是很常见的问题,后面避坑章节再细说。
3.3 任务的发起与审批:第一个完整闭环
部署完流程定义,我们来走一遍完整流程:启动实例、查询任务、审批任务。下面的代码假定流程里有一个用户任务节点,审批人字段是assignee。
// 启动流程实例 RuntimeService runtimeService = processEngine.getRuntimeService(); ProcessInstance instance = runtimeService .startProcessInstanceByKey("leave"); System.out.println("流程实例 ID:" + instance.getId()); // 查询这个实例下某个人待办的任务 TaskService taskService = processEngine.getTaskService(); List<Task> tasks = taskService.createTaskQuery() .processInstanceId(instance.getId()) .taskAssignee("zhangsan") .list(); System.out.println("待办数量:" + tasks.size()); // 审批第一笔任务 if (!tasks.isEmpty()) { taskService.complete(tasks.get(0).getId()); }startProcessInstanceByKey用的是 BPMN 文件里process元素的id属性,不是文件名。流程启动后,TaskQuery里taskAssignee用的昵称是租户处理人,不是数据库表里的用户主键。如果查出来的任务数量是 0,先确认你查询条件写对没有,大概率是assignee没设或者设给了别人。complete之后引擎会自动推进流程走向下一个节点,如果后面还有任务,再次用taskService查询就能看到新任务。
4. 把指南落进 Spring Boot:事务、表前缀与流程可视化
到目前为止我们用的是独立引擎,真实业务很少这么干。绝大多数项目会把流程引擎嵌进 Spring Boot,让引擎的事务与业务事务共用一个DataSource和TransactionManager。这一章的配置项,都是中文用户指南里容易一笔带过、但实际部署时异常关键的参数。
4.1 集成 Spring Boot 的初始化配置
我们常用的是基于activiti-spring自动装配的方式。在application.yml里配置好数据源,引擎启动时会复用同一份数据源,避免出现“引擎连一个库、业务连另一个库”的尴尬局面。
spring: datasource: url: jdbc:mysql://localhost:3306/activiti_test?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver activiti: database-schema-update: true history-level: full db-history-used: true async-executor-activate: falsedatabase-schema-update: true在集成模式下依然只建议开发环境开启。history-level: full记录所有流程变量快照、活动实例信息,适合后续做审批历史追溯。async-executor-activate: false是很多人会忽略的坑:如果流程里没有定时器、异步延续等需求,关掉异步执行器能少很多后台线程和死锁日志。等你真的需要异步节点时,再打开并把线程池参数调好。
引擎的事务边界可以用一个简单的架构说明:每次服务方法调用,都会在一个事务里执行完从任务查询到任务提交的全部动作。Spring 配置的事务管理器会包住这个边界,所以你不必手动调用saveOrUpdate,只要方法正常返回,整个流程节点推进、变量更新就一并提交了。若方法中途抛出异常,所有已执行的任务操作也会回滚。
4.2 任务监听器:业务流程里最常被用错的扩展点
用户指南里必然有“监听器”这一节,但很多人要么不用,要么把监听器当成万能钩子,在create事件里写一堆业务代码。常见做法是,用任务监听器给任务指定处理人,或动态设置任务截止时间。下面是一个在任务创建时自动指定审批人的示例。
public class DeptManagerTaskListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { // 任务创建时设置处理人 if (EVENTNAME_CREATE.equals(delegateTask.getEventName())) { // 这里可以从业务表查询实际审批人 delegateTask.setAssignee("dept-manager"); } } }在 BPMN 文件中给用户任务节点加入监听器配置:
<userTask id="approveTask" name="部门审批"> <extensionElements> <activiti:taskListener event="create" class="com.example.listener.DeptManagerTaskListener"/> </extensionElements> </userTask>监听器的执行时机在任务插入数据库之后,引擎提交事务之前。这里最容易踩的坑是:在监听器里调用了外部服务,而外部服务又依赖数据库查询,结果因为事务还没提交,查不到刚创建的任务。解决办法有两种:要么把外部调用改成事件发布,等事务提交后异步处理;要么在监听器里直接使用DelegateTask传过来的流程变量,尽量减少反向查询。
4.3 让非技术人员看到流程:动态生成流程图
用户指南会提到一个实用的能力:根据流程实例的运行位置,生成一张标记了当前节点的流程图。这在给业务方演示“流程走到哪一步”时特别有用。开发阶段很多人卡在中文乱码,这里给一个可用方案。
// 生成当前流程实例的流程图 ProcessDiagramGenerator generator = processEngine.getProcessDiagramGenerator(); BpmnModel bpmnModel = repositoryService .getBpmnModel(processInstance.getProcessDefinitionId()); InputStream diagram = generator.generateDiagram( bpmnModel, "宋体", "宋体", "宋体", processEngine.getRepositoryService(), highLightedFlows, highLightedNodes);generateDiagram方法的三组字体参数分别控制节点名称、事件名称和备注文字,必须传入服务器上真实存在的字体,否则中文全部显示成方框。highLightedFlows是高亮的连线 ID 集合,highLightedNodes是当前活动节点 ID 集合,把运行中任务的节点 ID 传进去,生成的图就会把当前步骤标红。这个功能建议封装成一个独立接口,业务方随时可以查看流程图,比让他们翻数据库直观得多。
5. Activiti 6 中文 用户指南 落地避坑:5 个高频翻车点
文档归文档,实际部署时总会冒出一些“文档里写了但你根本没注意”的问题。这一章整理了我自己和身边同事在这些年踩过的 5 个高频坑,每条都是现象、原因、解决一条龙。有些问题网上讨论很多,但中文资料里往往只有零散答案,这里集中写清楚。
5.1 流程任务和流程图里的中文全部变成问号
现象:引擎部署正常,但在任务列表里看名称是“???”,调用流程图生成接口,图片里的中文全是方框。
原因有两层。第一层是数据库连接没有指定 UTF-8 字符集,MySQL 默认排序规则可能让中文在写入时变成乱码;第二层是服务器操作系统缺少对应的中文字体,或者 JVM 默认字符集不是 UTF-8。
解决:数据库连接串必须像前面写的那样加上useUnicode=true&characterEncoding=utf8;生成流程图时把字体参数明确指定为服务器上存在的字体,并确认系统装了fontconfig和相应字体包。也可以在 JVM 启动参数里加上-Dfile.encoding=UTF-8,避免某些环境默认使用 GBK。
5.2 引擎启动时报 schema 版本不匹配
现象:项目第一次启动,抛出类似“Could not update Activiti database schema”或版本号对应不上的异常ActivitiWrongDbException。
原因:这台机器上的数据库里已经存在一套其他版本引擎建的表,常见于之前跑过 Activiti 5.x 的演示项目。表结构里ACT_GE_PROPERTY会记录当前 schema 版本,6.x 引擎发现留存版本不同就拒绝写入。
解决:在开发环境,直接把所有ACT_*表全部删掉,让引擎重建;如果是联调环境,先备份数据再删表重建。不要试图手动改ACT_GE_PROPERTY的版本号硬凑,Activiti 6 的表结构和老版本差异很大,硬改只会引发后面更隐蔽的 SQL 报错。生产环境的升级需要做完整的数据迁移脚本,而不是删表。
5.3 流程部署成功但任务查询结果始终为空
现象:deployment.deploy()执行成功,流程实例也能启动,taskService.createTaskQuery().list()却返回空。
原因:最常见的是查询条件写错。assignee对应的是办理人在引擎中的用户 ID,但流程 XML 里写的是候选组或候选人,例如activiti:candidateGroups="hr",这时任务没有明确的assignee,用taskAssignee查当然查不到。第二个常见原因是任务在并行网关之后,查询时任务还没创建到数据库,需要等异步逻辑执行完。
解决:排查时先去掉所有过滤条件,直接查整个流程实例下的任务列表,确认任务存在后再回推条件写法。候选组方式用taskCandidateGroup查询,候选用户方式用taskCandidateUser查询。如果任务确实没生成,检查流程引擎日志里有没有节点跳转失败,或者监听器里抛出的异常被吞掉。
5.4 集成后 Spring Boot 版本与 Activiti 6 不匹配
现象:应用能启动,但一旦调用引擎服务,就抛出NoSuchMethodError、ClassNotFoundException,或者 Bean 注入失败的提示。
原因:Activiti 6 的 Spring 集成代码是在特定版本 Spring 环境下编译的,如果项目的 Spring Boot 版本升得非常高,自动配置类里引用的某些内部类路径已经变了。最常见的是spring-jdbc与spring-tx的 API 变化,导致引擎装配时找不到方法。
解决:做项目选型时,先确认要用的 Activiti 6 对应推荐的 Spring Boot 版本范围,尽量保持主版本一致。如果团队坚持使用较新的 Boot 版本,就不要依赖它的自动配置,改为显式声明ProcessEngineConfiguration和ProcessEngineBean,完全自主控制版本依赖方向。这条经验也提醒我们:非必要不要混用工作流引擎和最新框架,工作流引擎的价值是稳定。
5.5 中文文档版本与实际引擎代码版本不同步
现象:照着 docx 里的配置项写,启动时发现某个属性已经不存在,或者属性名提示是错误的。
原因:翻译和整理的文档往往基于引擎某个早期发行版本,后续引擎补丁、修复没有同步更新到这份中文文档里,比如某些set方法改名、某些 XML 配置被新注解替代。这是离线知识库的通病,不是这份文档独有。
解决办法:以 jar 包内部源码为准。把activiti-engine源码包下到本地,遇到参数不生效时直接搜索对应类的setXxx方法,看是否还对外暴露。文档的价值是建立整体概念和常用路径,具体细节必须对照本地依赖版本。
6. 用户指南吃透之后:给流程模型建立回归测试和体检
当你照着一份中文用户指南把一个引擎跑通、把第一批业务流程部署上线后,真正的长期工作才刚刚开始。工作流引擎最怕的不是写不出来,而是改坏了没人知道。我习惯把流程模型当成业务代码一样维护,给每个流程建一个最小回归测试,每次改动流程 XML 或监听器,跑一遍再说。
6.1 一个能跑的开发期回归测试模板
public class LeaveProcessTest { private ProcessEngine processEngine; @Before public void setup() { processEngine = ProcessEngines.getDefaultProcessEngine(); } @Test public void shouldCompleteLeaveProcess() { ProcessInstance pi = processEngine.getRuntimeService() .startProcessInstanceByKey("leave"); Task task = processEngine.getTaskService().createTaskQuery() .processInstanceId(pi.getId()).singleResult(); Assert.assertNotNull("流程启动后应生成第一个任务", task); processEngine.getTaskService().complete(task.getId()); // 断言流程实例已结束 Assert.assertEquals(0, processEngine.getHistoryService() .createHistoricProcessInstanceQuery() .processInstanceId(pi.getId()) .finished() .count()); } }这个模板的意义不仅仅是验证“流程能走通”,而是每次改动后能快速感知流程结构是否被破坏。比如你给中间节点加了一个必填变量,旧测试立刻会挂,方便尽早发现。把这份测试跑在内存数据库上,几秒钟就能完成,不需要真实环境。
6.2 通过历史数据做一次引擎体检
等流程跑了一段时间,ACT_HI_PROCINST和ACT_HI_TASKINST里的数据就是你优化流程的最好依据。我常用的几个统计维度包括:流程实例平均完成时长、某个人或某个组的平均处理时长、挂起超过 7 天的实例列表。这些数据用一遍HistoryService查询出来,导成报表,能直接指出流程瓶颈出在哪个节点。经常有同事找我说“流程卡住了”,我打开历史表一看,往往是在某个审批人手里停了三四天,这其实不是引擎问题,是流程设计问题。工作流引擎能帮你把“停留时长”记录下来,但推动人去审批,还得靠业务机制。
6.3 把离线知识库变成团队常态
这份中文用户指南的价值会随着使用而递减,因为引擎版本总在变。我现在的做法是,把它当成团队新人的入门教材,但在项目内部另维护一份实践笔记,按真实项目形态记录配置项和踩坑记录。新人先读 docx 了解整体,再对照实践笔记接入具体项目,两三天就能上手。每当发现与文档描述不符的地方,顺手在原文档里做批注,定期组织统一梳理。
以前我总迷信文档本身,遇到问题先翻书,后来吃过几次亏,才明白工作流引擎这类中间件的文档,更多是给你一个完整的认知框架。真正的细节边界,必须靠自己的代码和测试去验证。把流程定义当代码一样管理,把引擎配置当接口一样评审,项目才能走得更稳。希望帮到你。
本文还有配套的精品资源,点击获取