一、流程引擎的API和服务(services)
引擎的API是影响Activiti最常见的一种方法。我们一开始最关注的中心是ProcessEngine,像之前描述的那样,流程引擎可以被多种方式创建。从这个流程引擎里面,你能获得各个包含workflow/BPM方法的服务。流程引擎和这些获得的服务是线程安全的。所以你能为整个服务器保留这些中的一个引用。
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();
ProcessEngines.getDefaultProcessEngine();这个方法被调用之后,会首先初始化并且创建一个流程引擎,并且以后会一直返回同一个流程引擎。ProcessEngine.init()和ProcessEngine.destroy方法会被用来创建和关闭所有流程引擎的属性。
ProcessEngine这个类会被所有的activiti.cfg.xml和activiti-context.xml文件扫描到。对于所有的activiti.cfg.xml来说,流程引擎都会用一种典型的方式被创建。这种方式就是:
ProcessEngineConfiguration.
createProcessEngineConfigurationFromInputStream(inputStream).
buildProcessEngine()。
对于所有的activiti-context.xml来说,流程引擎会被用Spring的方式来创建。这种方式是:
首先Spring的应用上下文被创建,然后流程定义会在应用的上下文中获得。
所有的Services服务是没有国界的。这就意味着你可以很轻松的在一个集群的多个节点中运行Activiti,每一个都用到相同的数据库,并且在以前的调用中,哪一个机器实际上被执行不会出现错误。任何服务的调用都是同等的,不管它在哪里被执行。
当用流程引擎工作的时候,第一个被需要的服务大概就是RepositoryService。这个服务为管理、多个部署和流程定义都提供了操作。这里不作详细介绍,一个流程定义是BPMN 2.0的一个java相关。它是一个流程每一步的结构和行为的表现。一个部署包是Activiti引擎下的包的单元。一个部署包能包含多个BPMN 2.0 xml文件和其他的一些资源。一个部署包里面包含什么由开发者决定。这些包括从单一的流程BPMN 2.0文件到一个整个的流程包和相关的资源。RepositoryService允许去部署这样的包。部署一个部署包意味着这是上传到引擎中,引擎中的所有的流程在被存到数据库之前都会被检查和解析。从这点来看,这个部署包被系统能识别,并且任何流程都被包含进这个部署包中,这样的部署包现在才能被启动。
进一步说,这样的服务允许去:
- 为引擎在部署包和流程定义中提供查询
- 终止或者激活部署包作为整个或者特别的流程定义。终止意味着不能再在部署包和流程定义中进行操作,当然,激活意味着相反的操作。
- 取回各种各样的资源,比如包含部署包或者流程程序的文件。然后这些资源被引擎自动发布。
- 取回一个流程定义的pojo版本,这个版本能被用于用java比xml反省流程。
Tasks是BPM的核心,比如Activiti。它需要被系统中的真实用户所执行。在TaskService中,围绕着任务的每一件事情都是分组的。比如:
- 查询分配给人或组的任务
- 创建新的单独任务。这些任务都不跟流程实例有关。
- 操纵哪一个用户的任务被分配或者在一些方式下哪一些用户卷入到任务中。
- 请求或者完成一个任务。请求意味着有些人被分配到到任务,意味着这个人将会完成这个任务。完成意味着正在做任务的某一部分工作。
IdentityService是相当简单的。它允许对于用户和组的管理。在运行的时候,Activiti实际上不对用户作任何检查。这对于理解Activiti是很重要的。举个例子,一个任务能分配给任何人,但是如果系统知道这个用户,引擎不会去区分它。这是因为Activiti引擎也能和服务一起结合使用。
FormService是一个可选的服务。意味着Activiti没有FormService,也能正确的被使用,不会牺牲消失任何其他的功能。这个服务介绍了start form和task form的概念。一个start form是一个表单,这个表单在流程实例启动之前展现给用户。然而一个task form是一个用户想要去完成一个表单的时候,展示的表单。Activiti允许在BPMN 2.0的流程定义中去定义这些表单。
HistoryService暴露了所有被Activiti 引擎生成的历史数据。当流程执行的时候,一些数据能被引擎保留。比如流程实例开始的时间,谁做的哪个任务,这个任务完成花了多长时间,在这个流程实例中,哪个路径是被跟踪的等等。这个服务暴露了主要的访问数据的查询方法。
用activiti的时候,当编码自定义应用的时候,ManagementService是不需要的。它允许去取回数据库表信息和表的元数据。进一步说,它暴露了对计划的查询和管理操作。在Activiti里,计划被用于各种各样的事情,比如计时器,异步连续,延迟暂停/激活等。这些话题会在更多的细节中进行讨论。
要获得更多的关于服务和引擎API的详细信息,请参考doc文档。
二、异常策略
在activiti中,最基本的异常是org.activiti.engine.ActivitiException,一个未经检查的异常。这个异常在任何时间都能被API抛出,但是除非这个异常是发生在那些在doc文档中记录的那些特殊的方法。举个例子,从TaskService中抛出的一个异常:
/** * 当任务被成功执行的时候调用. * @param taskId 是要去完成的任务的ID,不能为空. * @throws ActivitiObjectNotFoundException 当给出的id没有任务存在的时候,会抛出异常. */ void complete(String taskId);
在上面的例子中,当传的id任务不存在时,会抛出一个异常。同样,因此在javadoc中明确的规定任务id不能为空,当传过来的是个null,就会抛出ActivitiIllegalArgumentException。
即使我们想避开一个大级别的异常,当在特殊情况下一些异常被抛出的时候,下面的子类会被添加。在经过process-execution或者API-invokation报的错如果不在下面列出的异常之内,他们通常都会抛出一个ActivitiException。
- ActivitiWrongDbException:当Activiti引擎发现在数据库概要和引擎版本不匹配的时候会抛此异常。
- ActivitiOptimisticLockingException:在数据保存的时候,当同时被访问相同数据进入的时候,引起的乐观所。会抛此异常。
- ActivitiClassLoadingException:当一个需要被加载的类没有找打或者正当加载的时候报错,就会抛出此异常。
- ActivitiIllegalArgumentException:
- ActivitiTaskAlreadyClamiedException:当一个任务已经被请求,然后调用taskService.clami(...)的时候,会抛出此异常。
像上述一样,和Activiti 引擎互动的方式就是通过org.activiti.engine.ProcessEngine这个类的实例暴露的服务。下面的代码片段假设了你有一个工作中的Activiti环境,你也能获取到一个有效的org.activiti.engine.ProcessEngine。如果你仅仅想要提炼出下面的代码,你能下载或者克隆Activiti unit test template(https://github.com/Activiti/activiti-unit-test-template),把它导入到你的IDE,并且添加一个testUserguideCode()方法到org.activiti.MyUnitTest 单元测试。
3.1 部署流程
通过ResponsitoryService访问的任何数据都与静态数据有关(比如流程定义)。概念地,每一个这样的静态的一部分数据,都是Activiti引擎'respository'的内容。
在src/test/resources/org/activiti/test文件夹中,创建一个新的xml文件,名字为VacationRequest.bpmn20.xml,下面是具体内容。这一节不会解释被用于上面例子中的xml的结构。
<?xml version="1.0" encoding="UTF-8" ?>
<definitions id="definitions"
targetNamespace="http://activiti.org/bpmn20"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn">
<process id="vacationRequest" name="Vacation request">
<startEvent id="request" activiti:initiator="employeeName">
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" type="long" value="1" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
<activiti:formProperty id="vacationMotivation" name="Motivation" type="string" />
</extensionElements>
</startEvent>
<sequenceFlow id="flow1" sourceRef="request" targetRef="handleRequest" />
<userTask id="handleRequest" name="Handle vacation request" >
<documentation>
${employeeName} would like to take ${numberOfDays} day(s) of vacation (Motivation: ${vacationMotivation}).
</documentation>
<extensionElements>
<activiti:formProperty id="vacationApproved" name="Do you approve this vacation" type="enum" required="true">
<activiti:value id="true" name="Approve" />
<activiti:value id="false" name="Reject" />
</activiti:formProperty>
<activiti:formProperty id="managerMotivation" name="Motivation" type="string" />
</extensionElements>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>management</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id="flow2" sourceRef="handleRequest" targetRef="requestApprovedDecision" />
<exclusiveGateway id="requestApprovedDecision" name="Request approved?" />
<sequenceFlow id="flow3" sourceRef="requestApprovedDecision" targetRef="sendApprovalMail">
<conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'true'}</conditionExpression>
</sequenceFlow>
<task id="sendApprovalMail" name="Send confirmation e-mail" />
<sequenceFlow id="flow4" sourceRef="sendApprovalMail" targetRef="theEnd1" />
<endEvent id="theEnd1" />
<sequenceFlow id="flow5" sourceRef="requestApprovedDecision" targetRef="adjustVacationRequestTask">
<conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'false'}</conditionExpression>
</sequenceFlow>
<userTask id="adjustVacationRequestTask" name="Adjust vacation request">
<documentation>
Your manager has disapproved your vacation request for ${numberOfDays} days.
Reason: ${managerMotivation}
</documentation>
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" value="${numberOfDays}" type="long" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" value="${startDate}" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
<activiti:formProperty id="vacationMotivation" name="Motivation" value="${vacationMotivation}" type="string" />
<activiti:formProperty id="resendRequest" name="Resend vacation request to manager?" type="enum" required="true">
<activiti:value id="true" name="Yes" />
<activiti:value id="false" name="No" />
</activiti:formProperty>
</extensionElements>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>${employeeName}</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
</userTask>
<sequenceFlow id="flow6" sourceRef="adjustVacationRequestTask" targetRef="resendRequestDecision" />
<exclusiveGateway id="resendRequestDecision" name="Resend request?" />
<sequenceFlow id="flow7" sourceRef="resendRequestDecision" targetRef="handleRequest">
<conditionExpression xsi:type="tFormalExpression">${resendRequest == 'true'}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow8" sourceRef="resendRequestDecision" targetRef="theEnd2">
<conditionExpression xsi:type="tFormalExpression">${resendRequest == 'false'}</conditionExpression>
</sequenceFlow>
<endEvent id="theEnd2" />
</process>
</definitions>
|
要让流程引擎认识我们的这个流程,我们必须先发布它。发布意味着引擎会解析BPMN 2.0xml文件给一些事情执行并且为包含在发布包中的每一个流程定义都会添加一个新的数据库记录。这样的好处是:当流程引擎重启的时候,它会一直所有已经发布的流程:
3.2 开始一个流程实例
在把流程定义部署到流程引擎之后,我们就能启动一个新的流程实例。对于每一个流程定义来说,会有很多典型的流程实例。当流程定义的一个流程实例正在运行期,这个流程定义是'buleprint'。
每一件和流程运行状态的事情,都会被RuntimeService监控。有各种各样的方法去启动一个新的流程实例。在下面的代码片段中,我们用我们在流程定义xml中定义的key去启动一个流程实例。我们也会在流程实例启动的时候,提供一些处理过的变量。因为第一个用户任务的描述会用到他们在它的表达式中。因为他们为一个确定的流程定义中的流程实例赋予意义的时候,这些变量通常会被用到。典型的来说,这些变量是让流程实例区别于其他实例的因素。
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("vacationMotivation", "I'm really tired!");
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacationRequest", variables);
// Verify that we started a new process instance
Log.info("Number of process instances: " + runtimeService.createProcessInstanceQuery().count());
3.3 正在完成的任务
当一个流程开始的时候,第一步会成为一个用户的任务。这是一个必须被系统用户执行的步骤。典型的来说,这样的用户将会有一个'inbox of tasks','inbox of tasks'列出了所有需要被这个用户完成的任务。下面的代码就展现了这样一个查询怎么被执行:
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for (Task task : tasks) { Log.info("Task available: " + task.getName());}
继续流程实例,我们需要完成这个任务。对于Activiti引擎来说,这意味着你需要这个任务。下面的代码断展示了怎么做的:
Task task = tasks.get(0);
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "false");
taskVariables.put("managerMotivation", "We have a tight deadline!");
taskService.complete(task.getId(), taskVariables);
流程实例会继续到下一步,在这个例子中,这又会成为第一个布骤,因为这个任务没有被审核过。
3.4 暂停和激活一个流程
暂停一个流程定义是可能的。当一个流程定义被暂停,一个新的流程实例不会被创建(一个异常将会被抛出)。通过RepositoryService去暂停一个流程定义。
repositoryService.suspendProcessDefinitionByKey("vacationRequest");
try {
runtimeService.startProcessInstanceByKey("vacationRequest");
} catch (ActivitiException e) {
e.printStackTrace();
}
重新激活一个流程定义,通常的调用repositoryService.activateProcessDefinitionXXX方法中的一个方法。
暂停一个流程实例也有可能。当暂停的时候,这个流程不会继续下去并且没有计划会被执行。暂停流程实例可以通过调用runtimeService.suspendProcessInstance()方法.再次激活流程实例可以调用runtimeService.activateProcessInstanceXXX方法。
3.5 进一步阅读
四、查询API
从引擎中查询数据有两种方法:查询API和本地查询。查询API允许完全安全的用流畅的API编程。你能添加各种各样的条件到你的查询中并且精确地排序。下面的代码是个例子:
List<Task> tasks = taskService.createTaskQuery() .taskAssignee("kermit") .processVariableValueEquals("orderId", "0815") .orderByDueDate().asc() .list();有时,你需要更强大的查询,用一个OR操作或者约束的查询,用API,你不能明确的实现。对于这种情况,我们介绍本地查询,本地查询允许你写自己的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();
五、表达式
Activiti用UEL去解析表达式。UEL代表统一表达式语言(Unifies Expression Language),并且是EE6的一部分。为了支持在所有环境中最新的UEL的所有特点,我们用JUEL的一个编辑版本。
表达式能被用在java service tasks/execution Listeners/Task Listener和Condition sequence flows。尽管有两种表达式类型,值表达式和方法表达式,Activiti概括了他们,以致于他们都能用在表达式需要的地方。
-
值表达式:值得解析。默认的,所有的进程变量都能被拿来用。所有的spring-beans也能拿来用在表达式中。下面是例子:方法表达式:引用一个有或者没有参数的方法。当引用一个没有参数的方法的时候,在方法名字的后面要确定去添加一个空的括号。传过来的参数可以是被他们自己解析的字符串或者表达式。举例:
-
${myVar} ${myBean.myProperty}
-
-
-
${printer.print()} ${myBean.addNewOrder('orderName')} ${myBean.doSomething(myVar, execution)}
-
在所有进程变量中最上面,有一小部分默认的对象变量是被用到表达式中的:
- execution:
- task:
- authenticatedUserId:
流程引擎是线程安全的类并且能被很容易的在多个线程中分享。在一个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()方法。它会去扫描activiti.cfg.xml文件,并且根据配置信息去创建一个流程引擎。如果你有多个这样的资源文件,你要确保他们都有不同的名字。 当流程引擎是需要的时候,它能用下面的方法取到。
当然,用任何一个创建流程引擎的变体方法中也是可能的。想配置信息中描述的那样。contextDestryed方法会委托ProcessEngines.destroy()。这样,所有初始化的流程引擎都会关闭。
ProcessEngines.getDefaultProcessEngine()
or
ProcessEngines.getProcessEngine("myName");
当然,用任何一个创建流程引擎的变体方法中也是可能的。想配置信息中描述的那样。contextDestryed方法会委托ProcessEngines.destroy()。这样,所有初始化的流程引擎都会关闭。
相关推荐
Activiti 提供了一个强大的API和直观的模型定义语言(BPMN),使得开发者能够快速构建和部署业务流程应用。 ### 2. Eclipse Activiti 5.12 插件特性 - **流程建模**:Eclipse 插件提供了图形化的流程建模工具,...
《Activiti API 用户指南》是针对企业流程自动化框架Activiti的重要参考资料,主要涵盖了Activiti的API使用、功能特性和实践案例。本指南旨在帮助开发者更好地理解和应用Activiti,提升工作效率,实现高效的企业流程...
Activiti6是一款强大的工作流引擎,...以上内容是Activiti6用户指南的概述,涵盖了从安装、配置到实际开发和部署的所有关键步骤。对于Java开发人员来说,掌握这些知识将有助于有效利用Activiti6构建高效的工作流系统。
activiti6.0 用户指南中文版activiti6.0 用户指南中文版activiti6.0 用户指南中文版
本指南聚焦于 Activiti 5.4 版本,该版本在之前的版本基础上进行了优化和增强,以提供更好的性能和用户体验。 在Activiti 5.4中,用户可以体验到以下关键知识点: 1. **流程定义**:Activiti 使用 BPMN 2.0...
本用户指南针对 Activiti 5.4 版本,旨在帮助开发者和新手深入理解其核心功能和用法。 在Activiti 5.4中,首先介绍的是它的安装与配置。这一部分会涵盖如何下载 Activiti 的发行版,如何在 Java 开发环境中集成,...
这个压缩包包含了 Activiti 的不同版本,包括 5.12、5.14 和 5.15,这些都是 Java 开发人员在构建企业级应用时可能会用到的组件。每个版本的 Activiti 设计师都是一个图形化的流程建模工具,帮助用户设计和调试工作...
1. **Activiti7简介**:介绍Activiti7的历史、设计理念和主要特性,包括它的轻量级架构、强大的API支持以及与BPMN 2.0标准的紧密集成。 2. **安装与配置**:详细讲解如何在Java环境中安装Activiti7,包括依赖库的...
通过本用户指南,读者将学习到如何配置和使用 Activiti 5.4,创建和执行业务流程,以及如何利用 Activiti 实现企业的业务自动化。同时,了解 Activiti 的最佳实践和注意事项,能够有效地规避潜在的问题,提升流程...
这个"activiti中文api(用户手册)"提供了详细的中文文档,对于初学者来说是一个非常宝贵的资源,可以帮助他们快速理解和应用Activiti。 一、Activiti简介 Activiti 是基于BPMN 2.0标准的轻量级工作流引擎,它支持...
以上提到的内容概述了Activiti 5.13用户指南的主要知识点和操作指南,涵盖了从环境配置、基础入门、API和服务使用、Spring集成、BPMN模型构建、表单处理、历史数据查询、工具使用到REST API集成的全方位知识体系。...
本用户指南是针对 Activiti 6.x 版本的中文版,旨在帮助开发者和管理员更好地理解和使用 Activiti。 一、Activiti 概述 Activiti 是由 Alfresco 公司开发并维护的 BPMN 2.0 规范实现,提供了一个轻量级、灵活且可...
### Activiti6 用户指南知识点详解 #### 一、概述与许可 - **许可协议**:Activiti6基于Apache V2许可证发布,这意味着它遵循开放源代码许可证条款,允许用户自由使用、修改和分发该软件及其衍生作品。 - **下载...
Activiti 5.4 用户指南
以上就是关于Activiti6.0用户手册的主要内容,涵盖了流程定义、实例、数据库表结构、事件处理、API对象、服务接口、流程操作以及Spring集成等关键知识点。了解并熟练掌握这些概念,将有助于构建和管理高效的企业级...
Activiti 是一个开源的工作流和业务自动化引擎,广泛应用于企业级应用中,提供流程定义、执行、监控等全面的功能。...在开发过程中,中文API文档将作为宝贵的指南,帮助开发者快速定位和解决问题。
### Activiti 5.8 用户指南关键知识点解析 #### 一、概述 **Activiti** 是一个开源的工作流引擎,用于构建业务流程自动化应用。它提供了简单易用的方式来定义业务流程,并通过流程引擎来执行这些定义。从 **...
这份"Activiti 5.4 用户指南(中文版)"是针对中国开发者和使用者的详细指导资料,旨在帮助他们更好地理解和应用 Activiti。 1. **BPMN 2.0**:Business Process Model and Notation 2.0 是一种图形化的表示方法,...
### Activiti用户指南知识点总结 #### 1. Activiti简介 Activiti是一个轻量级、可扩展的流程引擎,它允许您创建企业级流程和工作流应用。Activiti遵循Apache V2许可证发布,源代码托管在GitHub上,允许用户查看、...
通过阅读《Activiti5.4 用户指南(中文版)》.pdf,用户将能深入理解这些功能并学会如何在实际项目中运用 Activiti,实现高效、灵活的业务流程自动化。这份指南是学习和掌握 Activiti 5.4 的重要资源,对于 IT 专业...