Flowable4-Flowable API


Process Engine API和服务

API是与Flowable进行交互的最常见的方式. 最主要的就是 ProcessEngine, 从 ProcessEngine 中, 您可以获取包含工作流程/BPM方法的各种服务.

ProcessEngine和服务对象是线程安全的, 所以你可以保留对整个服务器的引用.

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();
DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();

ProcessEngines.getDefaultProcessEngine() 将在第一次被调用时初始化和构建流程引擎, 并且总是返回相同的流程引擎. 正确创建和关闭所有流程引擎可以使用ProcessEngines.init()和完成ProcessEngines.destroy().

ProcessEngines 类将扫描所有 flowable.cfg.xmlflowable-context.xml 文件. 对于 flowable.cfg.xml 文件, 流程引擎将以典型的Flowable方式构建:

ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()

对于所有的 flowable-context.xml 文件, 流程引擎都是以Spring的方式构建的: 首先创建Spring应用程序上下文, 然后从该应用程序上下文获取流程引擎.

RepositoryService 引擎工作时所需要的第一个服务. 这项服务提管理流程仓库,例如部署,删除,读取流程资源等.

deployment 是Flowable引擎内的包装单位. deployment 可以包含多个BPMN 2.0 XML文件和任何其他资源. 包含在deployment 中的资源或文件选择取决于开发人员.

process definition 定义了一个流程中不同步骤的结构和行为. 对于每个流程定义, 通常有许多实例同时运行.

此外, 这项服务允许你:

  1. 查询引擎已知的部署和流程定义.
  2. 暂停和激活整个部署或特定的流程定义. 暂停意味着不能对它们进行下一步的操作, 而激活是相反的, 并且能够再次进行操作.
  3. 检索各种资源, 例如引擎自动生成的部署或流程中包含的文件.
  4. 检索流程定义的POJO版本.

常用的流程定义文件扩展名有:bpmn20.xml和bpmn. 流程定义的图片一般用png格式.


RuntimeService

虽然 RepositoryService 主要是关于静态信息, 但 RuntimeService 正好相反.

RuntimeService 主要用于管理流程在运行时产生的数据(流程参数, 事件, 流程实例, 以及执行情况)以及对正在运行的流程进行操作的API.

系统用户需要执行的任务是Flowable等BPM引擎的核心. 而任务周围的任务都被分组到TaskService中, 如:

  1. 查询分配给用户或组的任务.
  2. 创建新的独立任务. 这些是与流程实例无关的任务.
  3. 操作向哪个用户分配任务或者哪个用户以某种方式参与任务.
  4. 声称和完成一项任务. 声称意味着有人决参与任务, 这也意味着该用户将完成该任务. 完成意味着完成任务的工作.

IdentityService

IdentityService是非常简单的. 它支持组和用户的管理(创建, 更新,
删除, 查询).

Flowable实际上不会在运行时对用户进行任何检查. 例如, 可以将任务分配给任何用户, 但是引擎不验证该用户是否被系统知晓. 这是意味着Flowable引擎也可以与LDAP, Active Directory等服务结合使用.


FormService

FormService 是一个可选的服务. 该服务引入了开始表和任务表的概念. 开始形式是流程实例启动前显示给用户的一种形式, 而任务形式是当一个用户要填写一份表的时候进行显示.


HistoryService

HistoryService 服务公开有关正在进行和历史进程实例的信息.

这与运行时信息不同, 因为此运行时信息仅在任何特定时刻包含实际运行时状态, 并且针对运行时进程执行性能进行了优化. 历史信息(谁做了哪些任务, 完成任务需要多长时间, 每个流程实例遵循哪条路径, 等等)经过优化, 易于查询, 并且永久保存.


ManagementService

ManagementService 为流程引擎上的管理和维护操作提供服务. 此外, 它还暴露了查询功能和作业管理操作. 作业在Flowable中用于各种事情, 如定时器, 异步延续, 延迟挂起/激活等等.


DynamicBpmnService

DynamicBpmnService 可以用来改变流程定义的一部分, 而无需重新部署. 例如, 可以在流程定义中更改用户任务的受理人或者更改服务任务的类名称.


异常

FlowableWrongDbException: 当Flowable引擎发现数据库模式版本和引擎版本之间不匹配时抛出.
FlowableOptimisticLockingException: 在同一数据项的并发访问导致数据存储区发生乐观锁时抛出.
FlowableClassLoadingException: 当没有找到请求加载的类时或加载时发生错误(例如JavaDelegates, TaskListeners, ...)时抛出.
FlowableObjectNotFoundException: 当一个被请求或被执行的对象不存在时抛出.
FlowableIllegalArgumentException: 表示在Flowable API调用中提供了非法参数的异常, 在引擎配置中配置了非法值, 或者提供了非法值,
或者在进程定义中使用了非法值.
FlowableTaskAlreadyClaimedException: 当一个任务已经被声明,taskService.claim(…​)被调用的时候抛出.


查询API

查询引擎有两种方式: 查询API和SQL查询.

查询API允许您使用API编程来安全的查询. 您可以为查询添加各种条件(所有这些条件都作为逻辑“与”一起应用).以下代码显示了一个示例:

List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("kermit")
    .processVariableValueEquals("orderId", "0815")
    .orderByDueDate().asc()
    .list();

有时您需要更强大的查询, 例如使用 OR 运算符的查询或使用查询API无法表达的约束.

对于这些情况, 我们有SQL查询, 它允许您编写自己的SQL查询. 返回类型由您使用的Query对象定义, 数据映射到正确的对象(Task, ProcessInstance, Execution, ...).

由于查询将在数据库中被触发, 因此必须使用数据库中定义的表名和列名称; 这需要一些有关内部数据结构的知识, 建议小心使用SQL查询. 表名可以通过API检索, 以保持依赖性尽可能小.

List<Task> tasks = taskService.createNativeTaskQuery()
  .sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) +
      " T WHERE T.NAME_ = #{taskName}")
  .parameter("taskName", "gonzoTask")
  .list();

long count = taskService.createNativeTaskQuery()
  .sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T1, " +
      managementService.getTableName(VariableInstanceEntity.class) + " V1 WHERE V1.TASK_ID_ = T1.ID_")
  .count();

变量

每个流程实例都需要使用数据来执行它所组成的步骤.

在Flowable中, 这个数据被称为变量, 它们被存储在数据库中. 在调用外部服务时, 变量可以用在表达式中(例如, 在专用网关中选择正确的传出序列流).

流程实例可以包含变量(称为流程变量), 也可以包含执行用户任务时包含的变量. 一个流程实例可以有任意数量的变量. 每个变量都存储在ACT_RU_VARIABLE数据库表中的一行.

所有 startProcessInstanceXXX 方法都有一个可选参数, 用于在创建和启动流程实例时提供变量.

ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);

变量可以在流程执行过程中添加

void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map<String, ? extends Object> variables);
void setVariablesLocal(String executionId, Map<String, ? extends Object> variables);

变量也可以被检索, 如下所示. 请注意, TaskService 上存在类似的方法. 这意味着任务(如执行)可以具有仅在任务期间处于活动状态的局部变量.

Map<String, Object> getVariables(String executionId);
Map<String, Object> getVariablesLocal(String executionId);
Map<String, Object> getVariables(String executionId, Collection<String> variableNames);
Map<String, Object> getVariablesLocal(String executionId, Collection<String> variableNames);
Object getVariable(String executionId, String variableName);
<T> T getVariable(String executionId, String variableName, Class<T> variableClass);

瞬态变量

瞬态变量是像变量一样的变量, 但不会被持久化.

以下内容适用于瞬态变量:

  1. 对于瞬态变量没有存储历史.
  2. 瞬态变量只能由setTransientVariable(name,value)设置, 但是在调用getVariable(name)时也会返回瞬态变量, 其原因是为了使表达式的写作变得容易, 并且使用变量的现有逻辑适用于这两种类型.
  3. 一个瞬态变量会隐藏一个具有相同名称的流程变量. 这意味着, 如果在流程实例上设置了流程变量和瞬态变量, 并调用getVariable("someVariable"), 则将返回瞬态变量值.
  4. 流程变量只能在流程定义中的下一个等待状态之前被访问. 这里, 等待状态意就是流程实例中保存数据的点.

您可以在常规变量暴露的大多数地方设置和获取瞬态变量:

  1. DelegateExecution 在 JavaDelegate 实现
  2. DelegateExecution 在 ExecutionListener 实现和DelegateTask上的TaskListener实现
  3. 在通过执行对象的脚本任务中
  4. 通过运行时服务启动流程实例时
  5. 完成任务时
  6. 调用runtimeService.trigger方法时

表达式

Flowable使用UEL进行表达式解析. UEL代表统一表达式语言(Unified Expression Language).
值表达式: 解析为一个值. 默认情况下, 所有的过程变量都可以使用.

$ {myVar} 
$ {myBean.myProperty}

方法表达式: 调用带或不带参数的方法. 当调用一个没有参数的方法时, 一定要在方法名之后加上空的圆括号. 传递的参数可以是字面值或自己解析的表达式.

$ {printer.print()} 
$ {myBean.addNewOrder('orderName')} 
$ {myBean.doSomething(myVar,execution)}

在所有的流程变量之上, 有几个可以在表达式中使用的默认对象:
execution: DelegateExecution 持有关于持续执行的附加信息.
task: DelegateTask持有关于当前任务的附加信息. 注意: 只适用于任务监听器评估的表达式.
authenticatedUserId: 当前通过身份验证的用户的ID. 如果没有用户通过身份验证, 该变量不可用.


Web应用程序中的流程引擎

这个 ProcessEngine 是一个线程安全的类, 可以很容易地在多个线程之间共享. 在Web应用程序中, 这意味着可以在容器启动时创建一次流程引擎,并在容器关闭时关闭引擎.

下面的代码片断展示了如何编写一个简单的 ServletContextListener 在简单的Servlet环境中初始化和销毁​​流程引擎:

public class ProcessEnginesServletContextListener implements ServletContextListener {

  public void contextInitialized(ServletContextEvent servletContextEvent) {
    ProcessEngines.init();
  }

  public void contextDestroyed(ServletContextEvent servletContextEvent) {
    ProcessEngines.destroy();
  }

}

contextInitialized 方法将委托给 ProcessEngines.init(). 这将 flowable.cfg.xml 在类路径中查找资源文件, 并创建一个ProcessEngine . 如果在类路径中有多个这样的资源文件, 请确保它们都有不同的名称.

当需要流程引擎时, 可以使用以下方法获取流程引擎:

ProcessEngines.getDefaultProcessEngine()

ProcessEngines.getProcessEngine("myName");

推荐阅读更多精彩内容