《Activiti实战》摘抄&笔记2

##用户与组及部署管理
用户和工作流 作为 工作流引擎的基础数据(基础组件),有必要先了解学会如何管理及其之间的关系,有助于接下来的学习和理解。
1)用户、组的关系(数据模型),及其管理——CURD的API;
2)流程定义的管理CURD,包括部署、删除、读取部署的资源文件;

###用户与组 IdentifyService是用来管理user和group的

用户 :User 在各种需要人工参与的系统中,用户和组是一个身份系统(身份模块)的基础,在Activiti中用户和组主要是应用与用户任务。

:Group 在Activiti中,组的类型分2种:assignment和security-role,前者是一种普通的岗位角色,是用户分配业务中的功能权限,后者是安全角色,可以从全局管理用户组织及整个流程的状态。

用户与组的关系 : MemberShip

用户任务中的用户与组
当不确定要将一个任务分配给哪个人处理时,就需要把任务指定给多个候选人或候选组,谁签收了这个任务,谁就可以办理任务。
候选组:activiti:candidateGroups 候选人:activiti:candidateUsers

###部署流程资源 流程资源:在启动流程或流程实例运行过程中会被读取,一般包含:
1)流程定义文件: 扩展名为bpmn20.xml和bpmn;
2)流程定义的图片:用BPMN2.0规范的各种图形描绘,一般用PNG格式;
3)表单文件:把表单内容保存在一个文件中,扩展名为form;
4) 规则文件:例如Drools的规则文件,其扩展名为drl

部署流程资源都是通过RepositoryServce的createDeployment()方法在创建DeploymentBuilder对象后调用不同的方法部署资源,包括classpath, InputStream, 字符串, zip格式压缩包。 部署是指把流程定义文件持久化到数据库。

一次部署可以包含单个或多个资源文件,调用一次DeploymentBuilder的deploy()方法即可称之为一次部署;部署对象可以记录本次部署时间,并且本次部署的资源文件记录中会关联本次部署ID。

部署的执行过程:“开始部署”开始一次部署操作,然后保存本次所有的资源到字节流库中,紧接着处理(解析)本次部署的资源,流程引擎内置了2个处理器(解析流程定义、解析规则文件)用来解析常用的格式,部署完成后可能还有一些触发器需要执行。

一个流程定义会对应一个图片资源。图片可以由引擎自动生成,或者与流程定义一起部署(压缩包方式),这样引擎不再自动生成图片资源,而是使用部署包中的图片资源。

##任务表单 动态表单 :使用activiti:formProperty, 表单字段定义在流程定义文件中。动态表单的字段以键值的形式存储在变量表(ACT_HI_DETAIL)中。
HistoricFormProperty, HistoricVariableUpdate
自定义表单的字段类型:org.activiti.engine.impl.form.AbstractFormType,内置支持:boolean, date,double,enum,long,string

外置表单 :流程运行时表单内容(从部署的表单文件中读取)会原样显示在页面,并支持动态表单的字段值的自动填充功能。外置表单除了配置一个文件的相对路径外还可以配置URL
Activiti支持自定义表单引擎以适应各种场景,默认的表单引擎是基于Juel实现的,该引擎可以计算表单文件中EL表达式作为表单内容,所以当调用FormService接口的getRendered*Form()方法后得到的内容是经过Form引擎处理过的。

普通表单 :直接把表单的内容写在表现层(JSP、JSF、HTML等)文件中,一个用户任务对应一个页面(或者将内容官方在一个文件中,根据节点判断显示哪部分内容)。这样的做法适用于业务相对固定、业务比较复杂、流程相对固定但表现层变化比较多的情况。有涉及到统一事务管理

业务和流程数据库分离
业务表和流程建立双向关系是可选的,这样做的目的是在查询时可以明确知道业务对应的流程数据ID,假如没有在业务中保存流程实例ID,那么两者联合查询要以流程为入口,如此在性能方面就大打折扣。这样做还有另外一个母的,那就是可以区分业务数据的状态,例如有些系统中会区分已启动流程和未启动流程的数据,根据业务数据的“PROCESS_INSTANCE_ID"字段是否为空可以很容易地查询不同状态的数据

##Activiti与容器集成 ###流程引擎工厂 ProcessEngineFactoryBean生成ProcessEngine
1)configureExpressionManager:SpringExpressionManager
2)configureExternallyManagedTransactions:
3)processEngineConfiguration.setBeans :

SpringProcessEngineConfiguration在ProcessEngineConfigurationImpl基础上增加功能:
1)事物管理器的配置:transactionManager;
2)自动部署流程定义:Collection<AutoDeploymentStrategy> deploymentStrategies & Resource[] deploymentResources:通过spring创建的流程可以自动把定义的资源部署到引擎中。部署的方式是利用Spring提供的Resource功能实现的,可以使用多种方式配置资源路径。使用DeploymentBuilder.enableDeplicateFiltring()排除重复的流程定义,只有流程数据库中没有和自动部署的流程定义相同的记录才会部署,否则会忽略,不会出现启动多次应用后部署多个版本的流程定义问题。

###表达式 在流程定义中几乎所有的属性都可以使用变量方式定义,这样可以在运行中灵活地设置。在流程定义文件中出现的判断条件的语句或者调用一个Bean的方法都成为表达式。对表达式的解析由JUEL根据UEL规范实现,之后Activiti又对JUEL进行扩展满足更多地需求。
示例:

${myVar}  
${myVar.name}	
${serviceBean.confirm()} 
${serviceBean.confirm('xxxx')}
${serviceBean.confirm(name,execution)}

**引擎内置的三个变量
1)execution : 此变量在运行阶段总是可以调用,对应接口org.activiti.engine.delegate.DelegateExecution,从该接口的get方法中看出可以获取那些信息。
2)task: DelegateTask接口,仅支持用户任务,而且先顶为expression类型的表达式。
3)authenticatedUserId:此变量尽在启动流程实例前调用IdentityService的setAuthenticatedUserId()方法时才会由引擎提供,使用ThreadLocal保存

在Activiti中表达式应用非常广泛,通过表达式可以动态计算(读取)一切可以计算的表达式,从而获取动态值。例如可以动态设置用户任务的办理人(activiti:assignee属性),执行一个Java Service任务,或者执行Execution监听器、Task监听器、还有在请假流程中排他分支的输出流条件判断等。
在Activiti中,所有表达式中出现的变量均需要实现序列化接口java.io.Serializable。这样能保存到数据库里。对于3个内置变量,仅能通过表达式获取,不能通过RuntimeService或TaskService的getVariable()方法获取。

使用Spring管理变量
使用Spring管理变量可以避免由引擎保存复杂变量(自定义Bean)到数据库。就是processEngineConfiguration.setBeans

###监听器 1)流程实例级别的监听器均要实现接口org.activiti.engine.delegate.ExecutionListener,此接口仅有一个方法且传入一个DeletegaExecution对象作为参数;
2)任务级别的监听器与流程实例需要实现接口org.activiti.engine.delegate.TaskListner,都需要实现一个notify()方法,但参数是DelegateTask,而表达式注入字段的类型则必须是Expression。

##邮箱服务

##多实例 多实例允许多个用户协作完成一个任务,或者批量处理某项任务等。配置了多实例特性的活动在流程运行时依次(顺序方式)或单次批量(并行方式)创建活动实例,实例的数量由不同的参数决定。
会签: 就是主办人联合其他有关人员联合办理的过程,例如主办单位下发公文,一般需要多个部门共同审核通过之后才允许对外发布。再如员工离职需要各个部门签字、盖章确认之后方可离职,这一过程也称为会签。会签就是多实例的一个经典适用场景。

###非用户任务 非用户任务可以直接指定任务实例的数量(引擎内部会循环创建任务实例),也就是多实例任务执行的次数;用户任务如果也像非用户任务一样指定任务的数量就显得没有意义,因为用户任务没有任务的办理人。因此非用红任务创建多实例任务,可以通过配置多实例任务的nrOfInstances参数来实 现,当然该参数可以配置为固定值,也可以通过变量方式动态配置。

多实例的内置变量:nrOfInstances、nrOfActiviInstances、nrOfCompletedInstances、loopCounter,可以直接应用于表达式中,也可由在任务监听类中获取内置变量以便协助处理业务逻辑。

###用户任务多实例 和Java Service一样,如果用户任务也通过设置loopCardinality元素的值来决定实例数量,就显得毫无意义,因为缺少了用户任务的主要特性——人,所以用户任务实例数量就需要由参与的人数决定。

会签一般由主办人发起,从用户组织树中选择几个参与人一同办理任务,如果用户任务设置了按照并行的方式处理,那么将一次创建多个(和选择的人数量相等)实例,并按照选择参与人的顺序依次把任务分配assignee给参与人。如果按照顺序的方式执行任务,首先会创建一个任务实例分配给第一个参与人,只有第一个参与人办理完任务之后才会创建第二个任务实例、第三个任务实例……,并依次按照参与人的顺序设置任务的办理人。
顺序方式办理 :顺序办理也可以称作排队办理,只有一个人办理完后面的人才可以继续办理。
并行方式办理
设置结束条件 :可以根据不同的比例提前结束会签completionCondition

###审批意见
审批意见是工作流引擎中一个不可缺少的模块,流程变量可以保存流程处理过程中的中间状态(一般用于条件判断),审批意见可以保存每隔任务(一般指用户任务)办理时产生的意见。 Activiti在TaskService接口中定义了3个意见有关的方法:
1)创建意见:addComment(String taskId, String processInstanceId, String Message)
2) 根据流程实例ID获取意见:getProcessInstanceComments(String processInstanceId)
3) 根据任务ID读取意见:getTaskAttachements(String taskId)

##子流程与调用活动
在代码中,一个方法的功能过多时会拆分为多个方法,对于流程设计也是如此,可以从业务层面抽象考虑,把不同阶段的任务抽取出来作为一个子流程subprocess处理,如此当业务发生变化时只需要把更改聚焦在不同的子流程上即可,主流程负责串联(输出流)多个子流程。子流程也是一个完整的流程,有启动事件、用户任务、输出流以及结束事件等。

我们在开发时经常会使用很多第三方的插件来完成特定功能,例如利用POI处理Excel,一般不会自己去写处理Excel的代码而是利用现有的通用组件完成。在实际业务中也经常会有这样的需求,对于财务工作中的付款流程,付款的步骤基本固定,有申请、审批、出纳付款等节点,如果一个系统中有多个地方需要付款,那就需要在每个业务流程中设计重复的付款流程(或者作为一个子流程)。这样设计明显有弊端——重复且难以维护。调用活动Call Activity正是用来解决业务流程中重复设计的问题,只要设计好一个通用(或共用)的流程后由其他流程引用即可,当通用的部分变动时,业务流程无需更改,仅更改通用流程即可。

###子流程 对于单个流程来说,默认表ACT_RU_EXECUTION(运行时执行实例表)的ID_字段和PROC_INST_ID字段的值是相同的,如果一个流程包含子流程,调用活动,多实例的等活动类型,有主流程触发(自动启动)的Execution对象是附属于主流程的,通过设置Execution记录的PARENT_ID_字段的值为主流程实例的ID作为维护关系的条件。

子流程可以“共享”主流程的所有变量,而且子流程设置的变量可以以主流程的执行实例ID作为依据,所以子流程在获取数据时使用主流程的执行实例ID(子流程对应的执行实例的PARENT_ID_字段值)就可以获取到主流程的变量。

###调用活动
如果说子流程是一个类中的一个private方法,只能被当前类调用,那么调用活动就更上一层,把一个通用的方法提取到一个独立的类中供所有的类使用。

与子流程不同:
1)调用活动是以“引用”的方式把一个流程作为主流程的一个活动,当输出流到达调用活动时引擎会自动启动一个独立的流程实例,并把主流程的执行实例作为上级执行实例;
2)使用callActivity代替了subProcess,使用属性calledElement的值定义了外部流程的流程ID,使用activiti:in标签定义了2个输入类型的变量,这样独立的付款流程就可以使用target属性的值作为变量名获取变量,因为调用活动不能读取调用方的变量,必须通过activiti:in显示地指定;
3)在表ACT_RU_EXECUTION中是以SUPER_EXEC_字段来建立主流程和调用活动之前的上下级关系;
4)历史流程表ACT_HI_PROCINST表通过SUPER_PROCESS_INSTANCE_ID_字段来建立主流程和调用活动之前的上下级关系

##事件 ###定时启动事件
在什么时候创建定时任务? 答案是在部署流程之后,引擎对部属的流程定义做一些初始化的工作,其中就包含了对定时作业的注册(插入一条定时作业记录),还有对消息事件的注册等等。

定时启动事件可以按照预设时间启动是因为引擎不断刷新数据库表ACT_RU_JOB的记录,根据时间匹配作业,命中之后就执行作业。

ACT_RU_JOB表的主要字段说明:
1)TYPE_ :作业类型,有message和timer两种类型;
2)RETRIES_ :触发失败后最大重试次数,也可以通过调用ManagementService#setJobRetries方法设置;
3)DUEDATE_ :执行时间。引擎正是讲此字段与当前时间进行比较,相同或已超过则执行作业;
4)HANDLER_TYPE_ :作业的处理类型。对于每一种类型都有对应的处理器handler,目前引擎支持的类型有:event事件,timer-start-event定时启动事件,timer-transition边界定时事件,timer-intermediate-transition定时中间事件,async-continuation异步执行的作业
5)HANDLER_CFG_ :作业的目标,和HANDLER_TYPE_联合起来决定执行哪个流程定义的哪个作业处理类型,对于定时启动事件来说一般就是流程定义ID了。

###消息启动事件
在部署流程之后引擎会在初始化中处理消息事件,把消息的类型注册到数据库(ACT_RU_EVENT_SUBSCR),在流程执行过程中遇到了消息类型事件或通过API触发消息事件会从该表读取数据,并且根据消息的属性调用消息处理器。

ACT_RU_EVENT_SUBSCR表的主要字段说明:
1)EVENT_TYPE_ : 事件类型。message表示消息类型;
2)EVENT_NAME_ : 消息名称。 触发消息时引擎会根据消息名称参数和这个字段进行匹配;
3)EXECUTION_ID_ :实例执行ID。如果一个流程以消息启动事件引导,则此字段为空,如果在流程允许中注册了消息事件,则此字段保存流程执行ID;
4)PROC_INST_ID :流程实例ID。同EXECUTION_ID_,只不过保存的是流程实例ID(与EXECUTION是一对多的关系);
5)ACTIVITY_ID :活动ID。如果根据字段EVENT_NAME_匹配到消息就应该触发哪个活动;
6)CONFIGUATION_: 消息的配置信息。对于消息类型来说这里保存的是流程定义ID

当调用startProcessInstanceByMessage方法时,根据匹配规则就能触发消息启动事件,从而启动一个流程实例。

###结束事件
正常结束的流程,历史任务的deleteReason是completed,由于终止结束事件而引起流程实例结束执行的,历史任务的deleteReasion是deleted

###边界事件
消息边界事件、信号边界事件的cancelActivity:
true:在消息边界事件触发后取消已注册的消息事件;
false:在消息边界事件触发后仍然保留已注册的消息事件,可以再次触发;

##用户任务与附件
###用户任务 ####更改用户任务的属性 到期时间Task#setDueDate,优先级Task#setPriority

####任务相关人员 Task#setOwner,Task#setAssignee
1)拥有人:在流程处理过程中产生的用户任务,其拥有人属性为空,可以通过调用API方式更改用户任务的拥有人;
2)办理人:如果将一个任务直接分配给某一个用户,则这个用户就是任务的办理人;如果用户包含在候选人列表中或属于候选组中,并签收了该任务,此时该用户就是该任务的办理人;
3)参与人: 可以为用户列表添加不同类型的人员参与该任务办理,例如添加一个用户参与该任务的贡献者(根据任务内容给出办理意见,可以将意见以批注的方式分享给参与人)。为任务添加参与人实际上是向表ACT_RU_IDENTITYLINK中插入一条数据;

####反签收任务 反签收是相对于签收动作来说,可以把已经签收的任务任务的办理人置空,这样任务又还原到未签收的状态,此功能对误签收的情况很有用。

反签收任务的API和签收任务的相同,唯一不同是在签收任务时需要传递任务ID和用户ID,而反签收只需要传递任务ID,用户ID参数以null代替即可。

注意:如果用户任务没有相关候选人与候选组,只想反签收动作会导致任务无人认领。

####候选人&候选组
通过TaskService#addUserIdentityLink(taskId,userId,identityLinkType)方法可以添加一个参与人,其中第三个参数identityLinkType支持多种参与人关系类型。引擎对于每一种参与人关系类型都有不同的处理方式:
1)assignee : 任务的办理人,不会向表ACT_RU_IDENTITYLINK中插入数据,和Task#setAssignee的功能一样(实际后台就是调用了这个方法后更新任务);
2)owner : 任务的拥有人,与assgnee一样,不插入数据仅仅调用Task#setOwner后更新任务;
3)candidate: 表示任务的候选(人或组),根据表中的2个字段(USER_ID_, GROUP_ID_)是否为空来判断是候选人还是候选组;
4)starter :如果在启动流程时设置了认证用户,则会向表ACT_RU_IDENTITYLINK中插入一条数据表示流程启动人;
5)participant :在添加候选人、候选组或者非引擎支持的关系类型时,引擎会以流程实例ID作为标志(仅设置PROC_INST_ID_字段值不设置TASK_ID_字段值)插入数据到表ACT_RU_IDENTITYLINK中,方便根据流程实例查询参与人数据。一般没有权限签收任务,仅提供参考意见;

###子任务 在办理任务时可能会遇到需要把任务分解的情况,例如拆分出多个子任务交给不同的人办理,在Activiti中可以通过TaskService接口创建子任务或者根据父任务查询子任务。

可以继续在子任务中添加子任务,最终形成一颗树状结构。

引擎为提高运行速度把流程数据状态划分为运行中和历史(归档)2种类型,每一种状态对应不同的数据表,在一个用户任务执行完成后将该任务从运行时任务表ACT_RU_TASK中删除,并设置历史任务ACT_HI_TASKINST表的结束时间,因为这2张表的主键ID是相同的,所以可以根据运行时ID查询历史任务。

###附件 在流程流转过程中经常会附带一些文件,这些文件由不同的任务办理人上传。Acitiviti支持2种附件类型:
1)文件,以二进制流的方式保存到数据库
2)外部链接,把url直接保存到附件对象的url属性中

###改进意见列表 意见列表是为了在任务办理时允许办理人、候选人、参与人发表意见。除了用户自行添加意见之外,引擎还会自动把一些事件记录到意见列表。

ACT_HI_COMMENT表的一些字段:
1)TYPE_ :值为comment表示手动添加的任务办理意见,值为event表示由其他操作自动插入作为操作记录存在;
2)ACTION_ :记录每一条记录的动作类型,AddComment表示手动添加的意见,AddAttachment表示记录是在创建附件时由引擎自动创建。
3)MESSAGE_ :操作动作,例如,当动作为AddUserLInk且消息为jenny_|_candidate时,表示用户jenny被添加到任务的候选人列表。

###任务委派 任务委派是一个任务本来分配给用户A(委派人),但是A由于某些原因不能处理任务,可以把这个任务委派给用户B(被委派人)代理,在用户B处理完成后将任务再次回归给用户A

转载于:https://my.oschina.net/braveCS/blog/706681

Writing this book was a life-changer for me. After I wrote Open Source ESBs in Action for Manning a few years ago, I focused on my daily job for some time, working with open source enterprise integration frameworks like Mule, Camel, ServiceMix, and Spring Integration. My work, over time, drove me to designing and developing processes and BPM , and I started using j BPM and WebSphere Process Server. Then I learned that the founder of the j BPM project, Tom Baeyens, was leaving JB oss to work on a new open source project, which was in stealth mode at that time (early 2010). When the first alpha version of Activiti was released, I told myself I had to contribute to that project, one way or another. A piece that was missing in the first stages of the Activiti project was an Eclipse plug-in. I had some email conversations with Tom about contributing the plug-in to Activiti. We met and he told me that his goal was to disrupt the process engine space with the Activiti project. My enthusiasm grew even more and I offered my time to start working on a first version of the Activiti Designer. Together with my former col- leagues, Tiese Barrell, Yvo Swillens, and Ron van Liempd, we were able to deliver a first version within a couple of months. As we became part of the Activiti developer community, my hands were itching to start writing a book about Activiti. I felt that a great open source process engine would need a detailed book to describe all the possibilities and potential it offers. Manning was eager to publish a book about Activiti, and, together with Ron, we started writing in the autumn of 2010. We had a hard time keeping up with the frequent releases and the new functionality that kept on coming. But, it also was a lot of fun to be able to write about a new functionality that was just (or about to be) released. After a few meet-ups with the Activiti developer community and a couple of nice dinners with the Activiti team, we began discussing the possibility of my joining Alfresco to work on Activiti. In May 2011, I accepted the offer and was able to begin working on Activiti full-time. In the meantime, the writing of this book fell a little behind schedule. There was so much interesting work to be done developing the Activiti Designer, working on the Activiti Engine, and starting in a new job, that time caught up with me. After I had settled in a bit, I took up the writing task again and began working on the remaining chapters. So here I am, at the end of the process. I’ve switched from being a consultant to an open source software engineer, and I’m close to completing my second book. And, just like with my previous book, I have a new family addition coinciding with the book’s release. I hope you will enjoy reading this book as much as I loved writing it!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值