Activiti——流程任务详解(一)

Activiti流程任务

任务是流程的核心元素之一,任务表示在流程中需要完成的工作。BPMN2.0中定义了多种任务,每种任务都有不同的属性,完成不同的工作。

1、BPMN2.0任务

BPMN2.0中定义了多种不同的任务,每种任务都有其特定的行为。BPMN2.0中定义的任务有Service Task、Send Task、Receive Task、User Task、Manual Task、Business Rule Task和Script Task。Activiti支持BPMN2.0中定义的大部分任务,并且对这些任务进行了相应的扩
展,例如Service Task在Activiti中可以体现为Java Service Task、Web Service Task等。

1.1、任务的继承

BPMN2.0为任务在流程文件中的定义提供了规范,遵守BPMN2.0规范的流程引擎都需要按照其提供的XML约束来定义流程,也可以根据流程引擎自身的需要添加额外的XML元素或者属性。BPMN2.0在定义流程文件的XML约束时,根据不同流程元素的特点,定义了整套流程元素的继承机制,关于任务的继承关系如图所示。
在这里插入图片描述

流程文件中全部的XML元素均直接或者间接继承于BaseElement,其中FlowElement下有两种子元素:FlowNode和SequenceFlow,即流程节点和顺序流,而FlowNode下有三类子元素:Activity(行为)、Event(事件)和Gateway(网关)。Activity表示流程中行为流程节点,流程中表示行为的元素有三类:SubProcess(嵌入子流程)、CallActivity(调用子流程)和Task(任务)。

1.2、XML约束

对于流程文件中的每个XML元素,BPMN2.0均提供了XML约束,任务元素的ML约束如代码所示。

<xsd:element name="baseElement" type="tBaseElement"/>
<xsd:complexType name="tBaseElement" abstract="true">
	<xsd:sequence>
		<xsd:element ref="documentation" minOccurs="0" maxOccurs="unbounded"/>
		<xsd:element ref="extensionElements" minOccurs="0" maxOccurs="1" /> 
	</xsd:sequence>
	<xsd:attribute name="id" type="xsd:ID" use="optional"/>
	<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>

<xsd:element name="flowElement" type="tFlowElement"/>
<xsd:complexType name="tFlowElement" abstract="true">
	<xsd:complexContent>
		<xsd:extension base="tBaseElement">
			<xsd:sequence>
				<xsd:element ref="auditing" minOccurs="0" maxOccurs="1"/>
				<xsd:element ref="monitoring" minOccurs="0" maxOccurs="1"/>
				<xsd:element name="categoryValueRef" type="xsd:QName" minOccurs="0" maxOccurs="unbounded"/>
			</xsd:sequence>
			<xsd:attribute name="name" type="xsd:string"/>
		</xsd:extension>
	</xsd:complexContent>
</xsd:complexType>

...

1.3、任务的类型

BPMN2.0有以下类型的任务。

  • Service Task:服务任务可以用于调用Web Service或者自动执行程序,Activiti中的Java Service Task、Web Service Task、Shell Task为BPMN2.0中定义的Service Task,对应的XML元素为serviceTask。
  • Send Task:发送任务表示处理向外部的流程参与人发送消息的工作,根据这个定义,Activiti中的Email Task属于这种任务,但是Activiti的官方文档却使用serviceTask元
    素来配置,而笔者在查看Activiti的源代码时发现,Activiti的这两种任务,既可以使用serviceTask元素进行配置,也可以使用sendTask元素进行配置,该任务对应的XML元素为sendTask。
  • Receive Task:接收任务是一种等待外部流程参与者发送消息的任务,换言之,当流程到达该任务时,需要外界告诉该任务接收到消息,它才会继续执行。对于该类任务,目前Activiti只对Java进行了实现,因此Activiti中只有Java Receive Task,Receive Task对应的XML元素为receiveTask。
  • User Task:用户任务是典型的流程元素之一,它表示需要有人参与的任务,对应Activiti中的User Task任务,XML元素为userTask。
  • Manual Task:手动任务并不需要任务的流程引擎或者应用的驱动,它会自动执行,在工作流中,它表示一种工作己经完成,工作流引擎不需要关心它是如何完成的。该任务对应的XML元素为manualTasl。
  • Business Rule Task:业务规则任务,主要用于向规则引擎发送请求参数,让其按照既定的业务规则进行运算并返回结果,当前Activiti只对JBoss的Drools规则引擎提供支
    持,对应的XML元素为businessRuleTask。
  • Script Task:脚本任务用于执行定义好的脚本程序,流程到达该任务后,这些脚本程序被执行,执行完成后任务结束,对应XML元素为scriptTask。

2、用户任务

一般的业务流程大多都会有人的参与,因此用户任务是最常用的任务,当流程到达用户任务时,用户任务会被分配到特定用户或者用户组。
在这里插入图片描述

在流程文件中,可以使用userTask元素定义一个用户任务:

<process id="process1" name="process1">
	<userTask id="usertask1">
		<documentation>task doc</documentation>
	</userTask>
	<startEvent id="startevent1" name="Start"></startEvent>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

在代码中定义了一个id为“usertask1”的用户任务,在userTask元素下定义了documentation子元素,该子元素是BaseElement定义的子元素,因此流程文件中的全部元素(除根元素外)均可以使用该子元素来配置描述信息。为userTask配置了描述信息,当流程启动并到达这个用户任务时,会将这里所配置的任务描述信息写入任务数据表
(ACT_RU_TASK)的DESCRIPTION字段中。如果需要在代码中获取这些信息,可以使用task的getDescription方法。

2.1、分配任务候选人

任务的候选人是指有权限对该任务进行操作的潜在用户群体,这个用户群体有权限处理(处理、完成)该任务。设置这种权限可以使用TaskService的addCandidateUser方法或者
addCandidateGroup方法(见8.2节),也可以通过XML配置的方式为任务分配候选人。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Task1">
		<potentialOwner>
			<resourceAssignmentExpression>
				<formalExpression>user(angus), group(management), boss
				</formalExpression>
			</resourceAssignmentExpression>
		</potentialOwner>
	</userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

用户可以作为多种角色被分配到流程活动中,BPMN2.0提供了humanPerformer和potentialOwner元素来实现角色的分配,代码使用了potentialOwner元素,该元素继承于resourceRole,resourceRole可以作为子元素被配置在Activity元素下,而Task就是Activity的子元素,那么就可以使用potentialOwner。

在formalExpression中,定义了用户“anugs”和用户组“management’”、“boss”为该任务的候选人,该配置的效果等同于在流程运行时使用TaskService的
addCandidateGroup方法和addCandidateUser方法,如果需要指定某个用户为该任务的候选人,则需要使用user(userId)这样的表达式,用户组的话,可以使用group(groupld)来指定。如果不使用user或者group而直接使用字符串,则会被直接视作用户组的ID,效果等同于
group(groupId)。

ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
// 部署流程文件
repositoryService.createDeployment().addClasspathResource("demo12/Candidate.bpmn").deploy();
// 启动流程
runtimeService.startProcessInstanceByKey("process1");
// 根据用户组查询任务
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("boss").list();
System.out.println("分配到boss用户组下的任务数量:" + tasks.size());
// 根据用户查询任务
tasks = taskService.createTaskQuery().taskCandidateUser("angus").list();
System.out.println("用户angus下的任务数量为:" + tasks.size());
分配到boss用户组下的任务数量:1
用户angus下的任务数量为:1

2.2、分配任务代理人

可以为一个任务分配多个候选人,而一个任务只允许有一个代理人。可以使用TaskService的setAssignee方法设置任务的代理人,设置了任务代理人后,ACT_RU_TASK表的
ASSIGNEE字段会被设置为相应的值。除了使用setAssignee方法外,还可以使用XML配置的方式分配任务代理人。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Task 1">
		<humanPerformer>
			<resourceAssignmentExpression>
				<formalExpression>user1</formalExpression>
			</resourceAssignmentExpression>
		</humanPerformer>
	</userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

2.3、权限分配扩展

可以使用Activiti的扩展属性来实现这个功能。BPMN2.0规范允许各个流程引擎对规范进行扩展,可以为规范中定义的流程元素添加个性化的属性,前提是不能与BPMN
2.0规范相违背。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Assignee" activiti:assignee="user1"></userTask>
	<userTask id="usertask2" name="Candidate User"
		activiti:candidateUsers="user1, user2"></userTask>
	<userTask id="usertask3" name="Candidate Group"
		activiti:candidateGroups="group1,group2"></userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="usertask2"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask2"
		targetRef="usertask3"></sequenceFlow>
	<sequenceFlow id="flow4" name="" sourceRef="usertask3"
		targetRef="endevent1"></sequenceFlow>
</process>

代码中使用activiti:assignee属性分配任务代理人,使用activiti:candidateUsers属性来分配任务候选人,使用activiti::candidateGroups来分配任务的候选用户组。

2.4、使用任务监听器进行权限分配

除了可以使用BPMN2.0的ML元素和Activiti的扩展属性来分配任务候选人和任务代理人外,还可以编写自定义的任务监听器,在监听器的实现中使用编码方式进行权限分配。在般的应用系统中,用户组和用户均有可能发生变化,将用户和用户组写死到流程文件中显然是不合适的,因此可以使用任务监听器进行动态权限分配。

public class UserTaskListener implements TaskListener {
    public void notify(DelegateTask delegateTask) {
        System.out.println("使用任务监听器设置任务权限");
        delegateTask.setAssignee("user1");
        delegateTask.addCandidateGroup("group1");
        delegateTask.addCandidateUser("user1");
    }
}
<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Assignee">
		<extensionElements>
			<activiti:taskListener event="create"
				class="pers.zhang.listener.UserTaskListener"></activiti:taskListener>
		</extensionElements>
	</userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
// 部署流程文件
repositoryService.createDeployment().addClasspathResource("demo12/TaskListener.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");
// 进行任务查询
List<Task> tasks = taskService.createTaskQuery().taskAssignee("user1").list();
System.out.println(tasks.size());
使用任务监听器设置任务权限
1

2.5、使用JUEL分配权限

Activiti默认对JUEL表达式提供支持,因此在进行任务权限分配时,也可以使用JUEL表达式来指定。使用JUEL可以直接调用自定义JavaBean里面的方法,例如可以使用
${object..method()}或者${object.field}来调用方法或者获取属性值,但是前提是该对象需要被设置到流程参数中。

<process id="process1" name="process1" isExecutable="true">
  <startEvent id="startevent1" name="Start"></startEvent>
  <userTask id="usertask2" name="Task 1" activiti:assignee="${authService.getUserAssignee()}"></userTask>
  <userTask id="usertask3" name="Task 2" activiti:candidateUsers="${authService.getCandidateUsers()}"></userTask>
  <userTask id="usertask4" name="Task 3" activiti:candidateGroups="${authService.getCandidateGroups()}"></userTask>
  <userTask id="usertask5" name="Task 4" activiti:assignee="${authService.lastUser}"></userTask>
  <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask2"></sequenceFlow>
  <sequenceFlow id="flow2" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
  <sequenceFlow id="flow3" sourceRef="usertask3" targetRef="usertask4"></sequenceFlow>
  <endEvent id="endevent1" name="End"></endEvent>
  <sequenceFlow id="flow4" sourceRef="usertask4" targetRef="usertask5"></sequenceFlow>
  <sequenceFlow id="flow5" sourceRef="usertask5" targetRef="endevent1"></sequenceFlow>
</process>
public class AuthService implements Serializable {
    private String lastUser = "angus";

    public String getLastUser() {
        return this.lastUser;
    }

    public AuthService() {
        System.out.println("create AuthService");
    }

    //使用方法为任务指定代理人
    public String getUserAssignee() {
        return "crazyit";
    }

    //使用方法为任务指定候选人
    public List<String> getCandidateUsers() {
        List<String> result = new ArrayList<String>();
        result.add("user1");
        result.add("user2");
        return result;
    }

    //使用方法为任务指定候选用户组
    public List<String> getCandidateGroups() {
        List<String> result = new ArrayList<String>();
        result.add("group1");
        result.add("group2");
        return result;
    }
}
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
// 部署流程文件
repositoryService.createDeployment().addClasspathResource("demo12/JUELAuth.bpmn").deploy();
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("authService", new AuthService());
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1", vars);
// 查询第一个任务
Task task = taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).singleResult();
System.out.println("第一个任务代理人:" + task.getAssignee());
//完成第一个任务
taskService.complete(task.getId());
// 查询第二个任务
task = taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).singleResult();
// 查询任务与用户的关联
List<IdentityLink> links = taskService.getIdentityLinksForTask(task.getId());
System.out.println("第二个任务的候选用户:");//结果2
for (IdentityLink link : links) {
    System.out.println("    " + link.getUserId());
}
//完成第二个任务
taskService.complete(task.getId());
// 查询第三个任务
task = taskService.createTaskQuery().singleResult();
links = taskService.getIdentityLinksForTask(task.getId());
System.out.println("第三个任务的候选用户组:");//结果2
for (IdentityLink link : links) {
    System.out.println("    " + link.getGroupId());
}
// 完成第三个任务
taskService.complete(task.getId());
// 查找第四个任务
task = taskService.createTaskQuery().singleResult();
System.out.println("第四个用户的代理人:" + task.getAssignee())

3、脚本任务

脚本任务由流程引擎执行,在定义脚本任务时,需要为流程引擎提供它可以解析并执行的脚本语言,流程到达脚本任务时,流程引擎会执行定义好的脚本,任务将会在脚本执行后完成。
使用以下配置片断可定义一个Script Task:

<scriptTask id="scripttaskl"name="Script Task"scriptFormat="juel">
<script></script>
</scriptTask>

定义一个脚本任务,需要指定脚本的格式,如果不指定,Activiti会认为提供的是UEL表达式。JUEL是统一表达式语言(Unified Expression Language)的Java实现。Activiti的流程文件中许多地方都可以使用JUEL表达式,例如User Task、Service Task、Script Task和网关等。

3.1、脚本任务

脚本任务支持多种脚本语言,前提是提供的语言与JSR-223规范兼容。随着PHP、Ruby、JavaScript等脚本语言的广泛使用,为了能在Java中使用这些脚本语言,从Java6开始,Java提供了JSR-223规范,该规范定义了Java对这些脚本语言进行解析与执行的标准,从而为Java执行这些脚本语言提供了可能。在Java6中,集成了Rhino作为默认的JavaScript引擎,而在Java8中将Rhino替换为Oracle Nashorn。

//创建脚本引擎管理对象
ScriptEngineManager manager = new ScriptEngineManager();
//获取JavaScript的脚本引擎
ScriptEngine engine = manager.getEngineByName("javascript");
//执行一段脚本
engine.eval("for (var i = 0; i < 5; i++) {print(i);}");

3.2、JavaScript脚本

Java默认支持执行JavaScript脚本,因此可以在Script Task中直接将JavaScript作为任务的脚本。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task"
		scriptFormat="javascript">
		<script><![CDATA[
			var myVar = "angus";
			execution.setVariable("user", myVar);	
		]]></script>
	</scriptTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<userTask id="usertask1" name="End Task"></userTask>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
repositoryService.createDeployment().addClasspathResource("demo12/JavaScriptTask.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");
// 获取在JavaScript中设置的参数
String user = (String)runtimeService.getVariable(pi.getId(), "user");
System.out.println("获取用JavaScript设置的参数:" + user);
获取用JavaScript设置的参数:angus

3.3、Groovy脚本

Groovy是基于JVM的一种动态语言,它结合了SmallTalk、Ruby等语言的特性,使用Groovy可以很好地与Java进行结合。Groovy官方提供的groovy-jsr223-2.4.8包中已经包含了JSR-223的实现,因此可以在脚本任务中指定使用Groovy脚本。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task" scriptFormat="groovy">
		<script>
			org.crazyit.activiti.GroovyScriptTask.print(execution);
		</script>
	</scriptTask>
	<userTask id="usertask1" name="End Task"></userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
repositoryService.createDeployment().addClasspathResource("demo12/GroovyScriptTask.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");

3.4、设置返回值

在任务脚本中,可以得到execution变量,并且可以使用execution的方法,代码中就使用了execution的setVariable方法设置流程参数,除此之外,直接在脚本中定义的变量,也会被设置为流程参数,例如以下的JavaScript脚本:

<script>
	var user1 = "a";
	var user2 = "b";
</script>

那么在获取参数时,可以根据“user1”来获取参数值“a”,也可以根据“user2”来获取参数值“b”,而并不需要使用execution.setVariable方法。对于Groovy脚本,使用以下代码可以设置流程参数:

<script>
	user1 = "a";
	user2 = "b";
</script>

同样,也可以根据“user1”和“user2”来获取相应的参数值,但是如果使用以下Groovy脚本,就不能设置流程参数:

<script>
	def user1 = "a";
	def user2 = "b";
</script>

如果在脚本中想将某些值作为参数设置到流程中,并且想显式指定变量名称,则可以为scriptTask元素加上activiti:resultVariable属性,属性值为参数的变量名称。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task"
		scriptFormat="groovy" activiti:resultVariable="user">
		<script>
			execution.id
		</script>
	</scriptTask>
	<userTask id="usertask1" name="End Task"></userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

3.5、JUEL脚本

除了可以使用支持JSR223规范的脚本语言外,默认情况下,还可以使用JUEL表达式,使用JUEL表达式可以进行值的输出和Java Bean的调用。在脚本任务中,同样支持使用UEL表达式。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task" scriptFormat="juel">
		<script>
			${myBean.print(execution)}
		</script>
	</scriptTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="endevent1"></sequenceFlow>
</process>
public class MyBean implements Serializable {
    
    public void print(Execution exe) {
        System.out.println("执行Java Bean的方法,流程ID为:" + exe.getId());
    }
}
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        RuntimeService runtimeService = engine.getRuntimeService();
        repositoryService.createDeployment().addClasspathResource("demo12/JUELScript.bpmn").deploy();
        Map<String, Object> vars = new HashMap<String, Object>();
        vars.put("myBean", new MyBean());
        // 启动流程
        ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1", vars);
执行Java Bean的方法,流程ID为:15009
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Activiti中,可以使用多实例子流程来处理并发任务。以下是一个简单的示例: 假设我们有一个主流程,其中包含一个子流程,子流程中有一个并发多实例任务,需要同时处理多个子任务。 1. 首先,在子流程中创建一个并发多实例任务,可以使用以下XML代码实现: ``` <subProcess id="subProcess1" name="Sub Process"> <multiInstanceLoopCharacteristics isSequential="false"> <loopCardinality>3</loopCardinality> <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 1}</completionCondition> </multiInstanceLoopCharacteristics> <userTask id="subProcessTask" name="Sub Process Task" /> </subProcess> ``` 上面的代码中,`multiInstanceLoopCharacteristics` 元素表示这是一个多实例任务,`isSequential="false"` 表示任务是并行处理的,`loopCardinality` 表示需要处理的子任务数量,这里设置为3。`completionCondition` 表示任务完成的条件,这里设置为当所有子任务都完成时,子流程才算完成。 2. 在主流程中调用子流程,可以使用以下XML代码实现: ``` <callActivity id="subProcessCall" name="Sub Process Call" calledElement="subProcess1" /> ``` 上面的代码中,`calledElement` 属性指定了被调用的子流程的ID,这里为 `subProcess1`。 3. 在子流程中处理多实例任务,可以使用以下Java代码实现: ``` public class SubProcessTaskDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { // 获取当前子任务的ID String subTaskId = execution.getCurrentActivityId(); // 处理子任务 System.out.println("Processing sub task " + subTaskId); } } ``` 上面的代码中,`execute` 方法是任务处理的入口。可以通过 `getCurrentActivityId` 方法获取当前子任务的ID,然后处理任务。 以上就是在Activiti中处理并发多实例子流程任务的简单示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值