基于设计模式的SpringBoot+Flowable实现撤回功能


基于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() {
        //this.snapshot = takeSnapshot();
        //可进行前置操作
        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对象构建 构造过程封装,提升可读性
观察者模式 审计日志记录与监控指标上报 事件驱动,系统解耦
命令模式 事务补偿与撤销操作 操作原子性保障,支持回滚机制

你可能感兴趣的:(设计模式,spring,boot,后端)