这是我参与更文挑战的第5天,活动详情查看: 更文挑战
监听器
Activiti7监听器
服务任务
-
概述
为了实现一个可以在流程执行过程中调用的类,这个类需要实现org.activiti.engine.delegate.JavaDelegate接口,并在execute方法中提供所需的逻辑。当流程执行到达此特定步骤时,它将执行该方法中定义的此逻辑,并以默认的 BPMN 2.0 方式保留活动。
-
举例
我们创建一个 Java 类,该类可用于将流程变量 String 更改为大写。这个类需要实现org.activiti.engine.delegate.JavaDelegate接口,这需要我们实现*execute(DelegateExecution)*方法。引擎会调用这个操作,它需要包含业务逻辑。流程实例信息,如流程变量等,可以通过DelegateExecution接口访问和操作。
public class ToUppercase implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
String var = (String) execution.getVariable("input");
var = var.toUpperCase();
execution.setVariable("input", var);
}
}
复制代码
注意:只有一个 Java 类的实例是为它在 上定义的 serviceTask 创建的。所有流程实例共享将用于调用execute(DelegateExecution)的相同类实例。这意味着该类不能使用任何成员变量并且必须是线程安全的,因为它可以从不同的线程同时执行。这也会影响字段注入的处理方式。在流程定义中引用的类(即通过使用activiti:class
)在部署期间不会被实例化。只有当流程执行第一次到达流程中使用该类的点时,才会创建该类的实例。如果找不到该类,ActivitiException
则会抛出一个。这样做的原因是您部署时的环境(更具体地说是classpath)通常与实际的运行时环境不同。例如在Activiti Explorer中使用ant或业务归档上传部署流程时,classpath不包含引用的类。
-
在xml中具体展示
要指定在流程执行期间调用的类,需要由activiti:class属性提供完全限定的类名。
<serviceTask id="javaService"
name="My Java Service Task"
activiti:class="org.bci.ToUppercase" />
复制代码
中断流程任务
org.activiti.engine.impl.pvm.delegate.ActivityBehavior
-
描述
实现org.activiti.engine.impl.pvm.delegate.ActivityBehavior接口可以访问更强大的ActivityExecution,比如有特殊的业务在执行当前任务后停顿在当前位置,等待您一个事物的触发。
-
任务模型Java代码
public class MyActivitiBehavior implements ActivityBehavior { private static final Logger LOGGER = LoggerFactory.getLogger(MyActivitiBehavior.class); @Override public void execute(DelegateExecution execution) { LOGGER.info("run my java ActivityBehavior {}", this); } } 复制代码
-
在xml中表达式
<serviceTask id="someTask" name="User Task" activiti:class="com.imooc.activiti.example.MyActivitiBehavior"/> 复制代码
-
事件监听器
-
概述
事件侦听器的唯一要求是实现
org.activiti.engine.delegate.event.ActivitiEventListener
。 -
举例
下面是一个监听器的示例实现,它将接收到的所有事件输出到标准输出,与作业执行相关的事件除外:
public class MyEventListener implements ActivitiEventListener {
@Override
public void onEvent(ActivitiEvent event) {
// 获取事件类型,事件类型有:创建实体类,实体类初始化,实体类更新,实体删除 ...
switch (event.getType()) {
case JOB_EXECUTION_SUCCESS:
System.out.println("A job well done!");
break;
case JOB_EXECUTION_FAILURE:
System.out.println("A job has failed...");
break;
default:
System.out.println("Event received: " + event.getType());
}
}
@Override
public boolean isFailOnException() {
// 此监听器的 onEvent 方法中的逻辑并不重要
// 能过滤失败日志
return false;
}
}
复制代码
-
isFailOnException方法解释
该
isFailOnException()
方法确定在onEvent(..)
调度事件时该方法抛出异常时的行为。如果false
返回,则忽略异常。当true
返回,异常不会被忽略,前进行执行命令失败。如果事件是 API 调用(或任何其他事务性操作,例如作业执行)的一部分,则事务将被回滚。如果事件监听器中的行为不是关键业务,建议返回false
。Activiti 提供了一些基本实现来促进事件监听器的常见用例。这些可以用作基类或作为示例侦听器实现;
- org.activiti.engine.delegate.event.BaseEntityEventListener:事件监听器基类,可用于监听特定类型实体或所有实体的实体相关事件。它隐藏了类型检查并提供了 4 种应该被覆盖的方法:
onCreate(..)
,onUpdate(..)
以及onDelete(..)
何时创建、更新或删除实体。对于所有其他实体相关事件,onEntityEvent(..)
调用 。
- org.activiti.engine.delegate.event.BaseEntityEventListener:事件监听器基类,可用于监听特定类型实体或所有实体的实体相关事件。它隐藏了类型检查并提供了 4 种应该被覆盖的方法:
在运行时添加侦听器
可以使用 API ( RuntimeService
)向引擎添加和删除其他事件侦听器:
请注意,重新启动引擎时不会保留在运行时添加的侦听器。
/**
* Adds an event-listener which will be notified of ALL events by the dispatcher.
* @param listenerToAdd the listener to add
*/
void addEventListener(ActivitiEventListener listenerToAdd);
/**
* Adds an event-listener which will only be notified when an event occurs, which type is in the given types.
* @param listenerToAdd the listener to add
* @param types types of events the listener should be notified for
*/
void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types);
/**
* Removes the given listener from this dispatcher. The listener will no longer be notified,
* regardless of the type(s) it was registered for in the first place.
* @param listenerToRemove listener to remove
*/
void removeEventListener(ActivitiEventListener listenerToRemove);
复制代码
执行监听器
-
执行监听器位置
org.activiti.engine.delegate.ExecutionListener
-
概述
执行侦听器允许您在流程执行期间发生某些事件时执行外部 Java 代码或评估表达式。
执行监听器捕获事件
- 流程实例的开始和结束。
- 采取过渡。
- 活动的开始和结束。
- 网关的开始和结束。
- 中间事件的开始和结束。
- 结束开始事件或开始结束事件。
以下流程定义包含 3 个执行侦听器:
<process id="executionListenersProcess">
// 第一个执行监听器
<extensionElements>
<activiti:executionListener class="org.activiti.examples.bpmn.executionlistener.ExampleExecutionListenerOne" event="start" />
</extensionElements>
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="firstTask" />
<userTask id="firstTask" />
<sequenceFlow sourceRef="firstTask" targetRef="secondTask">
// 第二个执行监听器
<extensionElements>
<activiti:executionListener class="org.activiti.examples.bpmn.executionListener.ExampleExecutionListenerTwo" />
</extensionElements>
</sequenceFlow>
<userTask id="secondTask" >
// 第三个执行监听器
<extensionElements>
<activiti:executionListener expression="${myPojo.myMethod(execution.event)}" event="end" />
</extensionElements>
</userTask>
<sequenceFlow sourceRef="secondTask" targetRef="thirdTask" />
<userTask id="thirdTask" />
<sequenceFlow sourceRef="thirdTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
复制代码
第一个执行监听器
第一个执行监听器在进程启动时收到通知。监听器是一个外部 Java 类(如ExampleExecutionListenerOne
)并且应该实现org.activiti.engine.delegate.ExecutionListener
接口。当事件发生时(在本例中为start
事件),该方法notify(ExecutionListenerExecution execution)
被调用。
public class ExampleExecutionListenerOne implements ExecutionListener {
public void notify(ExecutionListenerExecution execution) throws Exception {
// 设置本地变量
execution.setVariable("variableSetInExecutionListener", "firstValue");
execution.setVariable("eventReceived", execution.getEventName());
}
}
复制代码
也可以使用实现
org.activiti.engine.delegate.JavaDelegate
接口的委托类。然后可以在其他构造方法中重用这些委托类,例如 serviceTask 的委托
第二个执行监听器
进行转换时调用第二个执行监听器。请注意,该listener
元素没有定义event
,因为take
在转换时只触发事件。在event
转换上定义侦听器时,将忽略属性中的值。
第三个执行监听器
当执行到最后一个执行监听器,在监听器上不是一个clas而是一个expression,他在触发事件被评估/调用。
<activiti:executionListener expression="${myPojo.myMethod(execution.eventName)}" event="end" />
复制代码
脚本执行侦听器
-
概述
在 Activiti 5.12 中,我们还引入了一种新类型的执行侦听器,org.activiti.engine.impl.bpmn.listener.ScriptExecutionListener。此脚本执行侦听器允许您为执行侦听器事件执行一段脚本逻辑。
-
举例
<activiti:executionListener event="start" class="org.activiti.engine.impl.bpmn.listener.ScriptExecutionListener" > <activiti:field name="script"> <activiti:string> def bar = "BAR"; // local variable foo = "FOO"; // pushes variable to execution context execution.setVariable("var1", "test"); // test access to execution instance bar // implicit return value </activiti:string> </activiti:field> <activiti:field name="language" stringValue="groovy" /> <activiti:field name="resultVariable" stringValue="myVar" /> </activiti:executionListener> 复制代码
执行侦听器上的字段注入
-
概述
使用配置了该
class
属性的执行侦听器时,可以应用字段注入。这与使用的Service 任务字段注入机制完全相同,其中包含对字段注入提供的可能性的概述。
下面的片段显示了一个简单的示例流程,其中包含一个注入字段的执行侦听器。
<process id="executionListenersProcess">
<extensionElements>
<!- 执行监听器位置-!>
<activiti:executionListener class="org.activiti.examples.bpmn.executionListener.ExampleFieldInjectedExecutionListener" event="start">
<activiti:field name="fixedValue" stringValue="Yes, I am " />
<activiti:field name="dynamicValue" expression="${myVar}" />
</activiti:executionListener>
</extensionElements>
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="firstTask" />
<userTask id="firstTask" />
<sequenceFlow sourceRef="firstTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
复制代码
public class ExampleFieldInjectedExecutionListener implements ExecutionListener {
private Expression fixedValue;
private Expression dynamicValue;
public void notify(ExecutionListenerExecution execution) throws Exception {
execution.setVariable("var", fixedValue.getValue(execution).toString() + dynamicValue.getValue(execution).toString());
}
}
复制代码
该类ExampleFieldInjectedExecutionListener
连接了 2 个注入的字段(一个是固定的,另一个是动态的)并将其存储在过程变量中*var
*。
// bpmn 文件位置
@Deployment(resources = {"org/activiti/examples/bpmn/executionListener/ExecutionListenersFieldInjectionProcess.bpmn20.xml"})
public void testExecutionListenerFieldInjection() {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("myVar", "listening!");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("executionListenersProcess", variables);
Object varSetByListener = runtimeService.getVariable(processInstance.getId(), "var");
assertNotNull(varSetByListener);
assertTrue(varSetByListener instanceof String);
// 结果是固定注入字段和注入表达式的串联
assertEquals("Yes, I am listening!", varSetByListener);
}
复制代码
任务监听器
-
概述
一个任务监听器用于执行自定义Java逻辑或使用表达式执行一定的任务相关的事件。
任务监听器只能作为用户任务的子元素添加到流程定义中。请注意,这也必须作为BPMN 2.0 extensionElements和activiti命名空间的子项发生,因为任务监听器是 Activiti 特定的构造。
-
任务监听器在xml中表达式
<userTask id="myTask" name="My Task" > <extensionElements> <!- 任务监听器 -> <activiti:taskListener event="create" class="org.activiti.MyTaskCreateListener" /> </extensionElements> </userTask> 复制代码
任务监听器属性
- event(必需):各种任务监听器配置如下:
- create:在创建任务并设置所有任务属性时发生。
- assignment:当任务分配给某人时发生。注意:当流程执行到达用户任务时,首先会触发分配事件,然后再触发创建事件。这似乎是一个不自然的顺序,但原因是:当收到 create 事件时,我们通常希望检查任务的所有属性,包括受托人。
- complete:在任务完成时和任务从运行时数据中删除之前发生。
- delete : 发生在任务将被删除之前。请注意,它也会在通过 completeTask 正常完成任务时执行。
- class:必须调用的委托类。这个类必须实现
org.activiti.engine.delegate.TaskListener
接口。
public class MyTaskCreateListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
// Custom logic goes here
}
}
复制代码
- 表达式:(不能与类属性一起使用):指定事件发生时将执行的表达式。可以将
DelegateTask
对象和事件名称(使用task.eventName
)作为参数传递给被调用对象。
<activiti:taskListener event="create" expression="${myObject.callMethod(task, task.eventName)}" />
复制代码