工作流中的“Activity”。

在业务流程管理领域,一个Activity(活动)是工作流中的一个基本执行单元,它代表了一个具体的、原子性的任务或操作,
- 审批任务:“经理审批报销单”。
- 服务调用:“调用第三方API验证用户信息”。
- 数据处理:“计算订单总金额”。
- 人工任务:“数据录入员填写客户信息”。
- 系统自动任务:“自动发送邮件通知”。
在Java中实现这些Activity,主要有以下几种技术路线,从简单到复杂,从轻量到重量级:
轻量级:自定义代码实现
对于非常简单、固定的流程,你可以不引入任何框架,直接用Java代码硬编码或封装成方法来实现。
核心思想
将每个Activity实现为一个Java方法或类,然后在主流程代码中按顺序调用它们。

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

@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来推进流程,每个微服务本身也可以包含自己的子流程。
主流技术选型
- Camunda (Zeebe):专为云原生和微服务设计的轻量级、高性能工作流引擎,Zeebe是Camunda的商业产品,其核心是开源的,它专注于“编排”,非常适合分布式场景。
- Netflix Conductor / Temporal:同样是优秀的分布式工作流协调器,提供了强大的服务编排能力。
示例(以Camunda Zeebe为例)
流程定义(使用Zeebe Operator或Web Modeler)
流程图会定义一系列“任务”,每个任务都会调用一个外部服务(通过HTTP/gRPC)。
[开始] -> [创建订单] -> [库存检查] -> [支付] -> [发货] -> [结束]
工作流引擎(Zeebe)的行为
创建订单任务:Zeebe向order-service的/create端点发送一个工作。order-service处理完订单后,向Zeebe报告任务完成(或失败)。- Zeebe收到完成信号后,自动推进到下一个任务
库存检查。 库存检查任务:Zeebe向inventory-service的/check端点发送工作。- ...以此类推。
- 优点:
- 解耦:工作流引擎与业务服务完全解耦,通过API通信。
- 可扩展性:每个服务可以独立部署和扩展。
- 容错与重试:引擎可以管理任务的重试、超时和补偿事务。
- 云原生:非常适合Kubernetes等容器化环境。
- 缺点:
- 系统架构更复杂,需要维护一个额外的协调服务。
- 服务间的通信开销和一致性挑战(需要Saga等模式)。
总结与选型建议
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 自定义代码 | 非常简单的、固定的、一次性的流程。 | 简单、无依赖、快速上手。 | 紧耦合、难以维护、无法处理复杂逻辑。 |
| Activiti / Flowable | 中大型企业应用,流程复杂且需要持久化、人工任务、历史追溯等。 | 功能全面、标准化、关注点分离、可视化。 | 学习成本高、有一定性能开销。 |
| Camunda (Zeebe) / Conductor | 微服务架构下的分布式流程编排,需要高吞吐和容错能力。 | 解耦、可扩展、云原生、高性能。 | 架构复杂、需要额外协调服务。 |
如何选择?
- 如果你只是想在一个小模块里实现几个固定的步骤:自定义代码就足够了。
- 如果你的系统是一个复杂的单体应用,流程多变,涉及大量人工审批和自动任务:Activiti / Flowable 是不二之选,是Java工作流领域的“标准答案”。
- 如果你的系统已经或将要拆分为微服务,需要协调多个服务来完成一个端到端的业务:请直接选择Camunda Zeebe 或类似的分布式工作流引擎,这是未来的趋势。
