# 服务任务

服务任务不同于用户任务,不需要进行人工处理,是一种自动化的任务。当流程流转到服务任务时,会自动执行服务任务中边界的Java程序。 Java程序执行完毕之后,流程将沿着服务任务外出顺序流继续流转。

# 图形标记

foo

右上角的标识是用来区分任务类型,可以通过小扳手按需调整,右上角齿轮形状即表示服务任务。

# XML内容

<bpmn:serviceTask id="Activity_0kkx1gi" name="服务任务" />

# 调用逻辑

有3种方法来声明调用逻辑,用于指定服务任务所调用的Java类或Spring容器中的Bean

  • 通过activiti:class属性指定一个Java类
<bpmn:serviceTask id="Activity_0kkx1gi" name="服务任务" class="com.xx.xx.MyJavaDelegate" />

对应的Java代码

public class MyJavaDelegate implement JavaDelegate{

    @Override
    public void execute(DelegateExecution execution){
        //在这里编写业务代码
    }
}

通过这种方式,当流程流转到服务任务时,流程引擎将创建一个实例,该对象会复用,所有流程实例将共享相同的实例。
如果Java类中使用了成员变量,必须保障线程安全。

  • 通过delegateExpression使用委托表达式指定
<bpmn:serviceTask id="Activity_0kkx1gi" name="服务任务" delegateExpression="${delegatBean}" />

delegateBean是一个实现JavaDelegate接口的Bean

  • 通过expression属性使用UEL表达式指定
//不带参数
<bpmn:serviceTask id="Activity_0kkx1gi" name="服务任务" expression="${businessBean.count()}" />

//带参数
<bpmn:serviceTask id="Activity_0kkx1gi" name="服务任务" expression="${businessBean.count(execution, money)}" />

//相当于调用getTotal()方法
<bpmn:serviceTask id="Activity_0kkx1gi" name="服务任务" expression="${businessBean.total}" />

这种方式在表达式调用前需要将其初始化到流程变量中,或者注册到Spring容器中。不需要实现JavaDelegate,表达式必须指定方法名和属性名

# 异常处理

使用服务任务,当执行自定义逻辑时,经常需要捕获对应的业务异常,并在流程中进行处理。有以下几种方式

  • 抛出Bpmn Errors
public class ThrowBpmnErrorDelegate implement JavaDelegate{
    
    @Override
    public void execute(DelegateExecution execution){
        try{
            //自定义逻辑
        }catch (Exception e){
            throw new BpmnError("Business Exception")
        }

    }
}

这种方式只适用于业务异常,需要通过定义错误边界事件或错误事件子流程进行处理。技术上的应使用其他异常类型,通常不在流程内部处理。

  • 指定异常顺序流

在异常发生时,如果服务任务是通过class指定Java类,或者通过delegateExpression属性指定的委托类,实现了ActivityBehavior接口, 在其excute()方法中控制流程流程离开当前服务任务,沿着指定的外出顺序流继续流转。

public class Demo implements ActivityBehavior {

    @Override
    public void excute(DelegateExcution excetion){
        //改变服务任务的外出顺序流
        DelegateHelper.leaveDelagate(excetion, "xxFlow")

    }
}

# 在服务任务中使用流程引擎服务接口

某些场景,我们需要在服务任务调用RuntimeService启动一个新流程实例。可以用以下两种方式。

@Component("handleWarMessage")
@Slf4j
public class HandleWarMessageTask implements JavaDelegate {

    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        //Camunda 写法
        RuntimeService runtimeService = delegateExecution.getProcessEngine().getRuntimeService();
        //Activit, Flowable写法
         RuntimeService runtimeService = Context.getProcessEngineConfiguration().getRuntimeService();
    }
}

@Component("handleWarMessage")
@Slf4j
public class HandleWarMessageTask implements JavaDelegate {
    @Autowired
    private RuntimeService runtimeService;

    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        runtimeService.startProcessInstanceByMessage("myKey");
    }
}