Flowable7-BPMN 2.0结构

事件(Event)

事件用来表明流程的生命周期中发生了什么事. 事件总是画成一个圆圈.
在BPMN 2.0中, 事件有两大分类: 捕获(catching)或 触发(throwing) 事件.

捕获(Catching): 当流程执行到事件, 它会等待被触发. 触发的类型是由内部图表或XML中的类型声明来决定的. 捕获事件与触发事件在显示方面是根据内部图表是否被填充来区分的(白色的).

触发(Throwing): 当流程执行到事件, 会触发一个事件. 触发的类型是由内部图表或XML中的类型声明来决定的. 触发事件与捕获事件在显示方面是根据内部图表是否被填充来区分的(被填充为黑色).


事件定义

事件定义, 决定了事件的语义. 如果没有事件定义, 这个事件就不做什么特别的事情.

没有设置事件定义的开始事件不会在启动流程时做任何事情. 如果给开始事件添加了一个事件定义(比如定时器事件定义)我们就声明了开始流程的事件 "类型 " (这时定时器事件监听器会在某个时间被触发).


定时器事件定义

定时器事件是根据指定的时间触发的事件。可以用于开始事件, 中间事件或边界事件.
timeDate: ISO 8601格式指定一个确定的时间, 触发事件的时间.示例:

<timerEventDefinition>
    <timeDate>2011-03-11T12:13:14</timeDate>
</timerEventDefinition>

timeDuration: 指定定时器之前要等待多长时间, timeDuration可以设置为timerEventDefinition的子元素. 使用ISO 8601规定的格式 (由BPMN 2.0规定)。示例(等待10天)。

<timerEventDefinition>
    <timeDuration>P10D</timeDuration>
</timerEventDefinition>

timeCycle: 指定重复执行的间隔, 可以用来定期启动流程实例, 或为超时时间发送多个提醒. timeCycle元素可以使用两种格式, 第一种是
ISO 8601标准的格式. 示例(重复3次,每次间隔10小时):

<timerEventDefinition>
    <timeCycle>R3/PT10H</timeCycle>
</timerEventDefinition>

另外, 你可以使用cron表达式指定timeCycle, 下面的例子是从整点开始, 每5分钟执行一次:

0 0/5 * * * ?

注意: 第一个数字表示秒,而不是像通常Unix cron中那样表示分钟.

你可以在定时器事件定义中使用表达式, 这样你就可以通过流程变量来影响那个定时器定义. 流程定义必须包含ISO 8601(或cron)格式的字符串, 以匹配对应的时间类型.

  <boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
     <timerEventDefinition>
      <timeDuration>${duration}</timeDuration>
    </timerEventDefinition>
  </boundaryEvent>

注意: 计时器,只有当启用了异步执行(flowable.cfg.xml中的asyncExecutorActivate需要设置为true, 因为异步执行默认情况下禁用的).


开始事件

开始事件用来指明流程在哪里开始. 开始事件的类型(消息到达时开始还是等待特定时间间隔 等等), 定义了流程如何启动, 这通过事件中不同的小图表来展示. 在XML中, 这些类型是通过声明不同的子元素来区分的.

开始事件都是捕获事件: 最终这些事件都是(一直)等待着, 直到对应的触发时机出现.

在启动事件中, 可以指定以下Flowable特定属性:
initiator: 当流程启动时, 保存经过身份验证的用户标识的变量名称. 示例如下:

<startEvent id="request" flowable:initiator="initiator" />

经过身份验证的用户必须使用IdentityService.setAuthenticatedUserId(String) try-finally块中的方法进行设置, 如下所示:

try {
  identityService.setAuthenticatedUserId("bono");
  runtimeService.startProcessInstanceByKey("someProcessKey");
} finally {
  identityService.setAuthenticatedUserId(null);
}

空开始事件

空开始事件技术上意味着没有指定启动流程实例的触发条件. 这就是说引擎不能预计什么时候流程实例会启动. 空开始事件用于, 当流程实例要通过API启动的场景, 通过调用startProcessInstanceByXXX方法.

ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX();

图形表示法
空开始事件显示成一个圆圈,没有内部图表(没有触发类型)

XML表示
空开始事件的XML结构是普通的开始事件定义, 没有任何子元素(其他开始事件类型都有一个子元素来声明自己的类型)

<startEvent id="start" name="my start event" />

计时器开始事件

定时开始事件用来在指定的时间创建流程实例. 它可以同时用于只启动一次流程和应该在特定时间间隔启动多次的流程.

注意: 子流程不能使用定时开始事件.
注意: 定时开始事件在流程发布后就会开始计算时间. 不需要调用startProcessInstanceByXXX, 虽然也可以调用启动流程的方法, 但是那会导致调用startProcessInstanceByXXX时启动过多的流程
注意: 当包含定时开始事件的新版本流程部署时, 对应的上一个定时器就会被删除. 这是因为通常不希望自动启动旧版本流程的流程实例.

图形表示法
定时开始事件显示为了一个圆圈, 内部是一个表.

XML内容
定时开始事件的XML内容是普通开始事件的声明, 包含一个定时定义子元素.请参考定时定义查看配合细节.

示例: 流程会启动4次, 每次间隔5分钟, 从2011年3月11日 12:13开始计时.

<startEvent id="theStart">
  <timerEventDefinition>
    <timeCycle>R4/2011-03-11T12:13/PT5M</timeCycle>
  </timerEventDefinition>
</startEvent>

例如: 进程将在选定的日期开始一次

<startEvent id="theStart">
  <timerEventDefinition>
    <timeDate>2011-03-11T12:13:14</timeDate>
  </timerEventDefinition>
</startEvent>

顺序流

顺序流是连接两个流程节点的连线. 流程执行完一个节点后, 会沿着节点的所有外出顺序流继续执行.

图形标记
顺序流显示为从起点到终点的箭头. 箭头总是指向终点.

XML内容
顺序流需要流程范围内唯一的id, 以及对起点终点元素的引用.

<sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />

条件顺序流

可以为顺序流定义一个条件. 离开一个BPMN 2.0节点时, 默认会计算外出顺序流的条件. 如果条件结果为true, 就会选择外出顺序流继续执行. 当多条顺序流被选中时, 就会创建多条分支, 流程会继续以并行方式继续执行.

注意: 上面的讨论仅涉及BPMN 2.0节点(和事件), 不包括网关. 网关会用特定的方式处理顺序流中的条件, 这与网关类型相关.

图形标记
条件顺序流显示为一个正常的顺序流, 不过在起点有一个菱形. 条件表达式也会显示在顺序流上.

XML内容
条件顺序流定义为一个正常的顺序流, 包含conditionExpression子元素.

注意目前只支持tFormalExpressions, 如果没有设置xsi:type="", 就会默认值支持目前支持的表达式类型.

<sequenceFlow id="flow" sourceRef="theStart" targetRef="theTask">
  <conditionExpression xsi:type="tFormalExpression">
    <![CDATA[${order.price > 100 && order.price < 250}]]>
  </conditionExpression>
</sequenceFlow>

目前, conditionalExpressions只能与UEL一起使用.
下面的例子引用了流程变量的数据, 通过getter调用JavaBean.

<conditionExpression xsi:type="tFormalExpression">
  <![CDATA[${order.price > 100 && order.price < 250}]]>
</conditionExpression>

这个例子调用一个解析为布尔值的方法

<conditionExpression xsi:type="tFormalExpression">
  <![CDATA[${order.isStandardOrder()}]]>
</conditionExpression>

网关

网关用来控制流程的流向.

图形标记
网关显示成菱形图形, 内部有一个小图标. 图标表示网关的类型.


独占网关

独占网关(也叫异或(XOR)网关), 用来在流程中实现决策.

当流程执行到这个网关, 所有外出顺序流都会被处理一遍. 其中条件解析为true的顺序流(或者没有设置条件, 概念上在顺序流上定义了一个'true')会被选中,让流程继续运行.

注意这里的外出顺序流与BPMN 2.0通常的概念是不同的. 通常情况下, 所有条件结果为true的顺序流都会被选中, 以并行方式执行, 但独占网关只会选择一条顺序流执行. 就是说, 虽然多个顺序流的条件结果为true, 那么XML中的第一个顺序流(也只有这一条)会被选中, 并用来继续运行流程. 如果没有选中任何顺序流, 会抛出一个异常.

图形标记
独占网关显示成一个普通网关()比如,菱形图形), 内部是一个“X”图标, 表示异或(XOR)语义. 注意, 没有内部图标的网关, 默认为独占网关. BPMN 2.0规范不允许在同一个流程定义中同时使用没有X和有X的菱形图形.

XML内容
独占网关的XML内容是很直接的: 用一行定义了网关, 条件表达式定义在外出顺序流中. 参考条件顺序流获得这些表达式的可用配置.
参考下面模型实例

它对应的XML内容如下:

<exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" />

<sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1">
  <conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression>
</sequenceFlow>

<sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2">
  <conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression>
</sequenceFlow>

<sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3">
  <conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression>
</sequenceFlow>

任务

用户任务

用户任务用来设置必须由人员完成的工作. 当流程执行到用户任务, 会创建一个新任务, 并把这个新任务加入到分配人或群组的任务列表中.

图形标记
用户任务显示成一个普通任务(圆角矩形), 左上角有一个小用户图标.

XML内容
XML中的用户任务定义如下. id属性是必须的. name属性是可选的.

<userTask id="theTask" name="Important task" />

用户任务也可以设置描述.实际上所有BPMN 2.0元素都可以设置描述.
添加documentation元素可以定义描述.

<userTask id="theTask" name="Schedule meeting" >
  <documentation>
      Schedule an engineering meeting for next week with the new hire.
  </documentation>

...

描述文本可以用标准的Java方式从任务中获取:

task.getDescription()

持续时间
任务可以用一个字段来描述任务的持续时间. 可以使用查询API来对持续时间进行搜索, 根据在时间之前或之后进行搜索.

我们提供了一个节点扩展, 在任务定义中设置一个表达式, 这样在任务创建时就可以为它设置初始持续时间. 表达式应该是java.util.Date, java.util.String (ISO8601格式), ISO8601持续时间(比如PT50M)或null.

例如: 你可以在流程中使用上述格式输入日期, 或在前一个服务任务中计算一个时间. 这里使用了持续时间, 持续时间会基于当前时间进行计算, 再通过给定的时间段累加. 比如, 使用"PT30M"作为持续时间, 任务就会从现在开始持续30分钟.

<userTask id="theTask" name="Important task" flowable:dueDate="${dateVariable}"/>

任务的持续时间也可以通过TaskService修改或在TaskListener中通过传入的DelegateTask参数修改.

用户分配
用户任务可以直接分配给一个用户. 这可以通过humanPerformer元素定义. humanPerformer定义需要一个 resourceAssignmentExpression来实际定义用户. 当前, 只支持formalExpressions.

<process >

  ...

  <userTask id='theTask' name='important task' >
    <humanPerformer>
      <resourceAssignmentExpression>
        <formalExpression>kermit</formalExpression>
      </resourceAssignmentExpression>
    </humanPerformer>
  </userTask>

只有一个用户可以坐拥任务的执行者分配给用户. 在Flowable中, 用户叫做执行者. 拥有执行者的用户不会出现在其他人的任务列表中, 只能出现执行者的个人任务列表中.

直接分配给用户的任务可以通过TaskService像下面这样获取:

List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").list();

任务也可以加入到人员的候选任务列表中. 这时, 需要使用potentialOwner 元素. 用法和humanPerformer元素类似. 注意它需要指定表达式中的每个项目是人员还是群组 .

<process >

  ...

  <userTask id='theTask' name='important task' >
    <potentialOwner>
      <resourceAssignmentExpression>
        <formalExpression>user(kermit), group(management)</formalExpression>
      </resourceAssignmentExpression>
    </potentialOwner>
  </userTask>

使用potentialOwner元素定义的任务, 可以像下面这样获取(使用TaskQuery的发那个发与查询设置了执行者的任务类似):

List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit");

任务分配扩展
当分配不复杂时, 用户和组的设置非常麻烦. 为避免复杂性,可以使用用户任务的自定义扩展.
assignee属性: 这个自定义扩展可以直接把用户任务分配给指定用户.

<userTask id="theTask" name="my task" flowable:assignee="kermit" />

它和使用上面定义的humanPerformer效果完全一样.

candidateUsers属性: 这个自定义扩展可以为任务设置候选人.

<userTask id="theTask" name="my task" flowable:candidateUsers="kermit, gonzo" />

它和使用上面定义的potentialOwner效果完全一样. 注意它不需要像使用potentialOwner通过user(kermit)声明, 因为这个属性只能用于人员.

candidateGroups属性: 这个自定义扩展可以为任务设置候选组.

<userTask id="theTask" name="my task" flowable:candidateGroups="management, accountancy" />

它和使用上面定义的potentialOwner效果完全一样. 注意它不需要像使用potentialOwner通过group(management)声明, 因为这个属性只能用于群组.

candidateUsers 和 candidateGroups 可以同时设置在同一个用户任务中.


Java服务任务

java服务任务用来调用外部java类.

图形标记
服务任务显示为圆角矩形, 左上角有一个齿轮小图标.

XML内容
有4钟方法来声明java调用逻辑:

  1. 实现JavaDelegate或ActivityBehavior
  2. 执行解析代理对象的表达式
  3. 调用一个方法表达式
  4. 调用一直值表达式

执行一个在流程执行中调用的类, 需要在'flowable:class'属性中设置全类名.

<serviceTask id="javaService"
             name="My Java Service Task"
             flowable:class="org.flowable.MyJavaDelegate" />

也可以使用表达式调用一个对象. 对象必须遵循一些规则, 并使用flowable:class 属性进行创建.

<serviceTask id="serviceTask" flowable:delegateExpression="${delegateExpressionBean}" />

这里delegateExpressionBean是一个bean, 它实现了JavaDelegate在Spring容器中定义的接口.

要指定应评估的UEL方法表达式, 请使用属性flowable:expression

<serviceTask id="javaService"
             name="My Java Service Task"
             flowable:expression="#{printer.printMessage()}" />

printMessage将在名为的命名对象上调用方法(不带参数)printer.
也可以使用表达式中使用的方法传递参数:

<serviceTask id="javaService"
             name="My Java Service Task"
             flowable:expression="#{printer.printMessage(execution, myVar)}" />

这会调用名为printer对象上的方法printMessage. 第一个参数是DelegateExecution, 在表达式环境中默认名称为execution. 第二个参数传递的是当前流程的名为myVar的变量.
要指定执行的UEL值表达式, 需要使用flowable:expression属性.

<serviceTask id="javaService"
             name="My Java Service Task"
             flowable:expression="#{split.ready}" />

ready属性的getter方法, getReady(无参数), 会作用于名为split的bean上. 这个对象会被解析为流程对象和(如果合适)spring环境中的对象.

这里我只写了一部分, 大家可以参考这两个网址来学习网址1 网址2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,368评论 25 707
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,846评论 6 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • 文/陶子 满街都是漂亮纸张包着的红苹果,一棵棵圣诞树挂满礼物,圣诞老人,小麋鹿,漂亮的红袜子 ,明天是圣诞节,今天...
    5号陶子阅读 311评论 0 0
  • 儿子读了大学,我们成了羡慕的对象:“哇。你们现在好幸福啊,儿子离手了,不像我们天天被孩子缠着。” 我点点头说是的。...
    时光容易把人抛阅读 250评论 0 0