Java 工作流框架的前世今生,我从《activiti与flowable的区别》这篇文章了解到flowable是基于activiti发展而来的,官方文档中有段话:
image.png
也证明了flowable是fork自activiti

《flowable对比》这篇文章对比了业内流行框架以及它们往后的发展历程。
image.png

Activiti

快速入门

我参考了这篇文章《Spring Boot Activiti 整合工作流引擎开发》,指导你如何配置 ProcessEngineConfiguration 以及八大接口

深入

《Activiti就是这么简单》这篇文章比较细致的介绍了activiti

Flowable

Flowable 项目中包括 BPMN(Business Process Model and Notation)引擎、CMMN(Case Management Model and Notation)引擎、DMN(Decision Model and Notation)引擎、表单引擎(Form Engine)

资源

Get Started

创建流程引擎

  1. 引入pom.xml
  1. <dependencies>
  2. <dependency>
  3. <groupId>org.flowable</groupId>
  4. <artifactId>flowable-engine</artifactId>
  5. <version>6.5.0.event-SNAPSHOT</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.h2database</groupId>
  9. <artifactId>h2</artifactId>
  10. <version>1.3.176</version>
  11. </dependency>
  12. </dependencies>
  1. 创建 ProcessEngine
  1. package org.flowable;
  2. import org.flowable.engine.ProcessEngine;
  3. import org.flowable.engine.ProcessEngineConfiguration;
  4. import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
  5. public class HolidayRequest {
  6. public static void main(String[] args) {
  7. ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
  8. .setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1")
  9. .setJdbcUsername("sa")
  10. .setJdbcPassword("")
  11. .setJdbcDriver("org.h2.Driver")
  12. .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
  13. ProcessEngine processEngine = cfg.buildProcessEngine();
  14. }
  15. }

ProcessEngine 是一个线程安全的对象,所以只需创建一次就好。

This is a thread-safe object that you typically have to instantiate only once in an application.

  1. 加入日志(不是必须的)
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.21</version>
</dependency>

log4j.properties

log4j.rootLogger=DEBUG, CA

log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n

定义流程

image.png

如上图所示的流程图,在flowable中实际上是以xml格式存储的。(实际工作中,画此流程图应当使用Flowable Modeler)

下面的holiday-request.bpmn20.xml 是具体内容,holiday-request.bpmn20.xml需要放在src/main/resources文件夹下

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
  xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
  xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
  xmlns:flowable="http://flowable.org/bpmn"
  typeLanguage="http://www.w3.org/2001/XMLSchema"
  expressionLanguage="http://www.w3.org/1999/XPath"
  targetNamespace="http://www.flowable.org/processdef">

  <process id="holidayRequest" name="Holiday Request" isExecutable="true">

    <startEvent id="startEvent"/>
    <sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>

    <userTask id="approveTask" name="Approve or reject request"/>
    <sequenceFlow sourceRef="approveTask" targetRef="decision"/>

    <exclusiveGateway id="decision"/>
    <sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[
          ${approved}
        ]]>
      </conditionExpression>
    </sequenceFlow>
    <sequenceFlow  sourceRef="decision" targetRef="sendRejectionMail">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[
          ${!approved}
        ]]>
      </conditionExpression>
    </sequenceFlow>

    <serviceTask id="externalSystemCall" name="Enter holidays in external system"
        flowable:class="org.flowable.CallExternalSystemDelegate"/>
    <sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>

    <userTask id="holidayApprovedTask" name="Holiday approved"/>
    <sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>

    <serviceTask id="sendRejectionMail" name="Send out rejection email"
        flowable:class="org.flowable.SendRejectionMail"/>
    <sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>

    <endEvent id="approveEnd"/>

    <endEvent id="rejectEnd"/>

  </process>

</definitions>

具体标签的含义请参考官方文档

开启流程实例

Scanner scanner= new Scanner(System.in);

System.out.println("Who are you?");
String employee = scanner.nextLine();

System.out.println("How many holidays do you want to request?");
Integer nrOfHolidays = Integer.valueOf(scanner.nextLine());

System.out.println("Why do you need them?");
String description = scanner.nextLine();

RuntimeService runtimeService = processEngine.getRuntimeService();

Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employee", employee);
variables.put("nrOfHolidays", nrOfHolidays);
variables.put("description", description);
ProcessInstance processInstance =
  runtimeService.startProcessInstanceByKey("holidayRequest", variables);

注意 key: holidayRequest 是和xml中的process id一致的。