杰瑞科技汇

Java工作流中Activity如何实现与执行?

工作流中的“Activity”

Java工作流中Activity如何实现与执行?-图1
(图片来源网络,侵删)

在业务流程管理领域,一个Activity(活动)是工作流中的一个基本执行单元,它代表了一个具体的、原子性的任务或操作,

  • 审批任务:“经理审批报销单”。
  • 服务调用:“调用第三方API验证用户信息”。
  • 数据处理:“计算订单总金额”。
  • 人工任务:“数据录入员填写客户信息”。
  • 系统自动任务:“自动发送邮件通知”。

在Java中实现这些Activity,主要有以下几种技术路线,从简单到复杂,从轻量到重量级:


轻量级:自定义代码实现

对于非常简单、固定的流程,你可以不引入任何框架,直接用Java代码硬编码或封装成方法来实现。

核心思想

将每个Activity实现为一个Java方法或类,然后在主流程代码中按顺序调用它们。

Java工作流中Activity如何实现与执行?-图2
(图片来源网络,侵删)

示例

// 1. 定义一个Activity接口(可选,但推荐)
interface Activity {
    void execute(Context context);
}
// 2. 实现具体的Activity
class CreateOrderActivity implements Activity {
    @Override
    public void execute(Context context) {
        System.out.println("执行活动:创建订单");
        // ... 业务逻辑 ...
        context.setData("orderId", "ORD-12345");
    }
}
class ValidatePaymentActivity implements Activity {
    @Override
    public void execute(Context context) {
        System.out.println("执行活动:验证支付");
        // ... 业务逻辑 ...
        context.setData("paymentStatus", "SUCCESS");
    }
}
class ShipOrderActivity implements Activity {
    @Override
    public void execute(Context context) {
        System.out.println("执行活动:发货");
        // ... 业务逻辑 ...
    }
}
// 3. 主流程编排
public class SimpleWorkflow {
    public void run() {
        Context context = new Context(); // 上下文,用于传递数据
        // 按顺序执行Activity
        new CreateOrderActivity().execute(context);
        new ValidatePaymentActivity().execute(context);
        new ShipOrderActivity().execute(context);
        System.out.println("工作流执行完成!");
    }
}
  • 优点
    • 简单直观,无需额外依赖。
    • 适用于流程非常固定、逻辑简单的场景。
  • 缺点
    • 紧耦合:流程代码和业务逻辑混在一起。
    • 难以维护:流程稍有变动就需要修改主流程代码。
    • 缺乏灵活性:无法实现动态流程、分支、并行等复杂逻辑。

主流框架:Activiti / Flowable

这是目前在Java生态中最流行、最成熟的解决方案,它们是基于BPMN 2.0标准的开源工作流引擎,你通过可视化的BPMN流程图来定义流程,而Activity则以BPMN中的“任务”(Task)形式存在。

核心思想

使用BPMN 2.0标准来描述业务流程,引擎负责解析流程图并驱动流程执行,开发者只需要关注每个“任务”(Activity)的具体实现。

主要类型的Activity(任务)

  1. 用户任务:需要人工参与的任务,Activiti会生成一个任务记录到数据库,可以通过任务查询API(如TaskService)找到并分配给用户处理。
  2. 服务任务:自动执行的任务,由Java代码实现,这是最常见的Activity类型。
  3. 网关:控制流程的分支和汇聚(如排他网关、并行网关)。
  4. 开始/结束事件:流程的起点和终点。

示例(以Activiti为例)

步骤1:定义BPMN流程图 (order-process.bpmn20.xml)

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:activiti="http://activiti.org/bpmn"
             targetNamespace="Examples">
    <process id="orderProcess" name="订单处理流程">
        <startEvent id="start" />
        <sequenceFlow id="flow1" sourceRef="start" targetRef="createOrderTask" />
        <!-- 服务任务:创建订单 -->
        <serviceTask id="createOrderTask" name="创建订单" activiti:expression="${orderService.createOrder()}"/>
        <sequenceFlow id="flow2" sourceRef="createOrderTask" targetRef="paymentGatewayTask" />
        <!-- 服务任务:调用支付网关 -->
        <serviceTask id="paymentGatewayTask" name="调用支付网关" activiti:expression="${paymentService.charge()}"/>
        <sequenceFlow id="flow3" sourceRef="paymentGatewayTask" targetRef="paymentDecision" />
        <!-- 排他网关:支付判断 -->
        <exclusiveGateway id="paymentDecision" name="支付是否成功?"/>
        <sequenceFlow id="flow4" sourceRef="paymentDecision" targetRef="shipOrderTask">
            <conditionExpression xsi:type="tFormalExpression">${paymentService.isSuccess()}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow5" sourceRef="paymentDecision" targetRef="cancelOrderTask">
            <conditionExpression xsi:type="tFormalExpression">${!paymentService.isSuccess()}</conditionExpression>
        </sequenceFlow>
        <!-- 服务任务:发货 -->
        <serviceTask id="shipOrderTask" name="发货" activiti:expression="${shippingService.ship()}"/>
        <sequenceFlow id="flow6" sourceRef="shipOrderTask" targetRef="end" />
        <!-- 服务任务:取消订单 -->
        <serviceTask id="cancelOrderTask" name="取消订单" activiti:expression="${orderService.cancel()}"/>
        <sequenceFlow id="flow7" sourceRef="cancelOrderTask" targetRef="end" />
        <endEvent id="end" />
    </process>
</definitions>

步骤2:实现Service(Activity的具体逻辑)

Java工作流中Activity如何实现与执行?-图3
(图片来源网络,侵删)
@Service
public class OrderService {
    public void createOrder() {
        System.out.println("Activity: 创建订单");
        // ... 业务逻辑 ...
    }
    public void cancel() {
        System.out.println("Activity: 取消订单");
        // ... 业务逻辑 ...
    }
}
@Service
public class PaymentService {
    public void charge() {
        System.out.println("Activity: 调用支付网关");
        // ... 模拟支付 ...
        this.success = true; // 假设支付成功
    }
    public boolean isSuccess() {
        return this.success;
    }
    private boolean success = false;
}
@Service
public class ShippingService {
    public void ship() {
        System.out.println("Activity: 发货");
        // ... 业务逻辑 ...
    }
}

步骤3:启动流程

@SpringBootTest
public class ActivitiTest {
    @Autowired
    private RuntimeService runtimeService;
    @Test
    public void testStartProcess() {
        // 启动流程,流程引擎会根据BPMN文件自动执行服务任务
        runtimeService.startProcessInstanceByKey("orderProcess");
        // 你可以在控制台看到对应Activity的打印输出
    }
}
  • 优点
    • 关注点分离:流程定义(BPMN图)与业务逻辑(Java代码)完全分离。
    • 可视化:业务人员也能看懂和参与流程设计。
    • 功能强大:支持复杂流程、分支、并行、事务、历史管理、任务分配等。
    • 标准化:基于BPMN 2.0,业界通用。
  • 缺点
    • 学习曲线较陡,需要理解BPMN和引擎的API。
    • 引擎本身有一定开销,不适合超轻量级场景。

微服务架构:分布式工作流引擎

在微服务架构下,一个完整的业务流程会跨越多个服务,需要一个能够协调多个分布式服务的“编排引擎”。

核心思想

将工作流引擎作为独立的“协调服务”,它不执行具体业务逻辑,而是通过调用各个微服务的API来推进流程,每个微服务本身也可以包含自己的子流程。

主流技术选型

  1. Camunda (Zeebe):专为云原生和微服务设计的轻量级、高性能工作流引擎,Zeebe是Camunda的商业产品,其核心是开源的,它专注于“编排”,非常适合分布式场景。
  2. Netflix Conductor / Temporal:同样是优秀的分布式工作流协调器,提供了强大的服务编排能力。

示例(以Camunda Zeebe为例)

流程定义(使用Zeebe Operator或Web Modeler)

流程图会定义一系列“任务”,每个任务都会调用一个外部服务(通过HTTP/gRPC)。

[开始] -> [创建订单] -> [库存检查] -> [支付] -> [发货] -> [结束]

工作流引擎(Zeebe)的行为

  1. 创建订单任务:Zeebe向order-service/create端点发送一个工作。
  2. order-service处理完订单后,向Zeebe报告任务完成(或失败)。
  3. Zeebe收到完成信号后,自动推进到下一个任务库存检查
  4. 库存检查任务:Zeebe向inventory-service/check端点发送工作。
  5. ...以此类推。
  • 优点
    • 解耦:工作流引擎与业务服务完全解耦,通过API通信。
    • 可扩展性:每个服务可以独立部署和扩展。
    • 容错与重试:引擎可以管理任务的重试、超时和补偿事务。
    • 云原生:非常适合Kubernetes等容器化环境。
  • 缺点
    • 系统架构更复杂,需要维护一个额外的协调服务。
    • 服务间的通信开销和一致性挑战(需要Saga等模式)。

总结与选型建议

方案 适用场景 优点 缺点
自定义代码 非常简单的、固定的、一次性的流程。 简单、无依赖、快速上手。 紧耦合、难以维护、无法处理复杂逻辑。
Activiti / Flowable 中大型企业应用,流程复杂且需要持久化、人工任务、历史追溯等。 功能全面、标准化、关注点分离、可视化。 学习成本高、有一定性能开销。
Camunda (Zeebe) / Conductor 微服务架构下的分布式流程编排,需要高吞吐和容错能力。 解耦、可扩展、云原生、高性能。 架构复杂、需要额外协调服务。

如何选择?

  • 如果你只是想在一个小模块里实现几个固定的步骤自定义代码就足够了。
  • 如果你的系统是一个复杂的单体应用,流程多变,涉及大量人工审批和自动任务Activiti / Flowable 是不二之选,是Java工作流领域的“标准答案”。
  • 如果你的系统已经或将要拆分为微服务,需要协调多个服务来完成一个端到端的业务:请直接选择Camunda Zeebe 或类似的分布式工作流引擎,这是未来的趋势。
分享:
扫描分享到社交APP
上一篇
下一篇