基于SpringBoot+Flowable的流程撤回功能深度实践
一、需求场景与架构设计
1.1 业务流程撤回核心需求
- 场景覆盖:用户任务节点撤回、并行会签撤回、流程实例终止
- 核心约束:
- 时效性控制(如24小时内可撤回)
- 数据版本一致性校验
- 权限验证(发起人/管理员)
- 事务原子性保证
1.2 技术架构图
前端
REST API
RecallService
策略模式
责任链模式
命令模式
节点回退策略
流程终止策略
空值校验
时效校验
权限校验
事务补偿
二、RecallContext核心设计
2.1 上下文对象定义
public class RecallContext {
private String processInstanceId;
private ProcessInstance processInstance;
private Task currentTask;
private HistoricActivityInstance targetNode;
private Date targetNodeEndTime;
private String operator;
private Map<String, Object> variables;
private RecallType recallType;
private String auditLog;
private boolean success;
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final RecallContext context = new RecallContext();
public Builder processInstanceId(String id) {
context.processInstanceId = id;
return this;
}
public RecallContext build() {
validate();
return context;
}
private void validate() {
if (context.processInstanceId == null) {
throw new IllegalArgumentException("Missing processInstanceId");
}
}
}
}
2.2 上下文生命周期管理
@Component
public class RecallContextFactory {
@Autowired
private RuntimeService runtimeService;
@Autowired
private HistoryService historyService;
public RecallContext createContext(RecallRequest request) {
return RecallContext.builder()
.processInstanceId(request.getProcessInstanceId())
.targetNodeId(request.getTargetNodeId())
.operator(request.getOperator())
.variables(request.getVariables())
.build(runtimeService, historyService);
}
private HistoricActivityInstance queryTargetNode(String instanceId, String nodeId) {
return historyService.createHistoricActivityInstanceQuery()
.processInstanceId(instanceId)
.activityId(nodeId)
.singleResult();
}
}
三、设计模式综合应用
3.1 策略模式实现撤回算法
public interface RecallStrategy {
void execute(RecallContext context);
boolean supports(RecallType type);
}
@Component
public class RollbackStrategy implements RecallStrategy {
@Override
public void execute(RecallContext context) {
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(context.getProcessInstanceId())
.cancelActivityId(context.getCurrentTask().getTaskDefinitionKey())
.startActivityId(context.getTargetNode().getActivityId())
.changeState();
}
@Override
public boolean supports(RecallType type) {
return type == RecallType.ROLLBACK;
}
}
3.2 责任链模式实现校验流程
public interface RecallValidator {
void validate(RecallContext context);
void setNext(RecallValidator next);
}
public class TimeValidator implements RecallValidator {
private RecallValidator next;
@Override
public void validate(RecallContext context) {
Duration duration = Duration.between(
context.getTargetNodeEndTime().toInstant(),
Instant.now()
);
if (duration.toHours() > 24) {
throw new RecallException("超出撤回时限");
}
if (next != null) next.validate(context);
}
@Override
public void setNext(RecallValidator next) {
this.next = next;
}
}
3.3 命令模式实现事务管理
public interface RecallCommand {
void execute();
void undo();
}
public class RollbackCommand implements RecallCommand {
private final RecallContext context;
private final RecallStrategy strategy;
private String snapshot;
public RollbackCommand(RecallContext context, RecallStrategy strategy) {
this.context = context;
this.strategy = strategy;
}
@Override
public void execute() {
strategy.execute(context);
}
@Override
public void undo() {
restoreSnapshot(snapshot);
}
}
四、撤回服务核心实现
4.1 服务层实现
@Service
@Transactional
public class RecallService {
@Autowired
private RecallContextFactory contextFactory;
@Autowired
private List<RecallValidator> validators;
@Autowired
private StrategyManager strategyManager;
public void processRecall(RecallRequest request) {
RecallContext context = contextFactory.createContext(request);
validators.forEach(validator ->
validator.validate(context));
RecallStrategy strategy = strategyManager.getStrategy(request.getType());
new RollbackCommand(context, strategy).execute();
auditService.log(context);
}
}
4.2 策略管理器
@Component
public class StrategyManager {
private final Map<RecallType, RecallStrategy> strategies = new ConcurrentHashMap<>();
@Autowired
public StrategyManager(List<RecallStrategy> strategyList) {
strategyList.forEach(strategy ->
strategies.put(strategy.supports(), strategy));
}
public RecallStrategy getStrategy(RecallType type) {
return Optional.ofNullable(strategies.get(type))
.orElseThrow(() -> new UnsupportedOperationException("未支持的撤回策略"));
}
}
五、审计与监控增强
5.1 观察者模式实现日志记录
@Component
public class AuditListener {
@EventListener
public void handleRecallEvent(RecallSuccessEvent event) {
auditRepository.save(buildRecord(event.getContext()));
}
private AuditRecord buildRecord(RecallContext context) {
return AuditRecord.builder()
.operator(context.getOperator())
.processInstanceId(context.getProcessInstanceId())
.operationType("RECALL")
.detail(context.getAuditLog())
.build();
}
}
5.2 监控埋点示例
public class RecallMonitor {
private static final MeterRegistry registry = Metrics.globalRegistry;
public static void recordRecall(RecallContext context) {
Counter.builder("process.recall.count")
.tag("type", context.getRecallType().name())
.register(registry)
.increment();
}
}
六、性能优化实践
6.1 缓存优化设计
@Cacheable(value = "processCache", key = "#instanceId")
public ProcessInstance getInstance(String instanceId) {
return runtimeService.createProcessInstanceQuery()
.processInstanceId(instanceId)
.singleResult();
}
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
6.2 批量操作优化
public void batchRecall(List<String> instanceIds) {
List<RecallCommand> commands = instanceIds.stream()
.map(id -> new RollbackCommand(contextFactory.create(id)))
.collect(Collectors.toList());
commands.parallelStream()
.forEach(RecallCommand::execute);
}
七、完整测试案例
7.1 集成测试类
@SpringBootTest
public class RecallIntegrationTest {
@Autowired
private RecallService recallService;
@Test
void testRollbackScenario() {
deployProcess();
ProcessInstance instance = startProcess();
completeTask(instance.getId(), "apply");
RecallRequest request = new RecallRequest();
request.setProcessInstanceId(instance.getId());
request.setTargetNodeId("apply");
request.setType(RecallType.ROLLBACK);
recallService.processRecall(request);
Task currentTask = queryTask(instance.getId());
assertEquals("apply", currentTask.getTaskDefinitionKey());
}
}
八、设计模式总结
模式 |
应用场景 |
核心价值 |
策略模式 |
多种撤回算法选择 |
算法可扩展,避免条件分支膨胀 |
责任链模式 |
多层级校验规则处理 |
校验逻辑解耦,支持动态扩展 |
建造者模式 |
复杂RecallContext对象构建 |
构造过程封装,提升可读性 |
观察者模式 |
审计日志记录与监控指标上报 |
事件驱动,系统解耦 |
命令模式 |
事务补偿与撤销操作 |
操作原子性保障,支持回滚机制 |