• 从if-else地狱到流程编排天堂 写出优美代码就是这么简单
  • 发布于 1天前
  • 19 热度
    0 评论
  • 北风吹
  • 0 粉丝 60 篇博客
  •   
兄弟们,咱先聊个扎心的事儿 ,打开公司祖传的 Java 项目,想改个简单的业务逻辑,结果一翻代码,好家伙!一个方法里的 if-else 能嵌套到第 8 层,缩进比你工资条上的数字还长。改的时候大气不敢喘,生怕动了其中一个 else,整个系统就跟多米诺骨牌似的全崩了?我前阵子就踩过这坑。当时要给订单系统加个 “老用户专属折扣” 的逻辑,原代码里订单处理的方法长这样:
public void handleOrder(Order order) {
    // 第一步:判断订单类型
    if (order.getType() == OrderType.NORMAL) {
        // 普通订单判断支付方式
        if (order.getPayType() == PayType.WECHAT) {
            // 微信支付判断是否满减
            if (order.getAmount() >= 100) {
                // 满减后判断是否老用户
                if (order.getUser().isOldUser()) {
                    order.setDiscount(0.9);
                } else {
                    order.setDiscount(1.0);
                }
                wechatPayService.pay(order);
            } else {
                if (order.getUser().isOldUser()) {
                    order.setDiscount(0.95);
                }
                wechatPayService.pay(order);
            }
        } else if (order.getPayType() == PayType.ALIPAY) {
            // 支付宝支付又一套判断...
            if (order.getAmount() >= 200) {
                // 此处省略800字嵌套...
            }
        }
    } else if (order.getType() == OrderType.GROUP) {
        // 团购订单再来一套独立的if-else...
    }
    // 后面还有库存判断、日志记录、消息推送的嵌套...
}
改完这个逻辑,我眼睛都快成斗鸡眼了,测试的时候还漏了个 “新用户用支付宝支付满 150 减 20” 的场景,结果线上出了 bug,当晚加班到凌晨两点 —— 这 if-else,简直就是开发者的 “职场 PUA 神器”!后来我痛定思痛,把这套逻辑用流程编排重构了一遍,现在不管加什么新规则,都是 “插拔式” 操作,再也不用在嵌套里找不着北。今天就跟大家好好唠唠,怎么用流程编排跟 if-else 彻底说再见。

一、先别急着骂 if-else,咱得搞懂它为啥会 “癌变”
首先声明:if-else 本身没问题,就像菜刀能切菜也能伤人,问题出在 “用错地方” 和 “过度使用”。我见过很多项目里的 if-else,都是从 “一行简单判断” 慢慢长成 “千行嵌套怪物” 的,这个过程就叫 “逻辑癌变”。
咱先拿刚才的订单例子分析下,if-else 为啥会越写越烂:
1. 「逻辑耦合」:所有规则都挤在一个 “垃圾桶” 里
你看原代码里,订单类型、支付方式、满减规则、用户身份判断,全堆在handleOrder方法里。就像把衣服、鞋子、零食、化妆品全塞在一个衣柜里,刚开始还能翻找,越堆越多就彻底乱了。后来产品说 “要给新用户支付宝支付加个首单立减”,我得在支付宝支付的 else 分支里再塞一个 if;再后来又说 “老用户团购订单额外 9 折”,我又得在团购订单的分支里加判断 —— 每加一个新规则,就是在 “垃圾桶” 里多扔一件东西,最后谁也分不清里面到底有啥。

2. 「扩展性差」:改一行代码,像拆一颗炸弹
有次我要把 “满 100 减 10” 改成 “满 100 减 15”,按理说只是改个数字,但因为这个判断藏在微信支付的 if 分支里,我得先理清 “订单类型是普通订单→支付方式是微信→金额满 100→用户是新用户” 这个链路,生怕改的时候碰了其他判断条件。更坑的是,有些判断条件还互相依赖。比如 “是否老用户” 的判断,既用在普通订单里,又用在团购订单里,后来产品改了 “老用户定义”(从注册满 1 年改成满 6 个月),我得在代码里找遍所有用到isOldUser()的 if 分支,改漏一个就出 bug—— 这哪是改代码,这是拆炸弹啊!

3. 「可读性为零」:新人看代码,得先画思维导图
我同事刚接手这个项目的时候,看这个handleOrder方法看了一下午,最后在笔记本上画了个思维导图,才理清里面的逻辑。他跟我说:“这代码里的 if-else,比我老家的族谱还复杂,光分支就有 12 个。”

其实这还不算最夸张的,我见过有人写的代码,if-else 嵌套到第 11 层,缩进能从屏幕左边排到右边,中间还夹杂着各种临时变量和魔法值 —— 这种代码,除了写的人自己,没人能一次看懂。

4. 「测试噩梦」:想覆盖所有场景,得写 100 个测试用例
因为每个 if-else 分支都是独立的场景,要保证测试覆盖,就得把所有分支都跑一遍。刚才的订单例子,光订单类型(2 种)× 支付方式(2 种)× 金额区间(3 种)× 用户身份(2 种),就有 2×2×3×2=24 种场景,还没算上异常情况。每次加新规则,测试用例就得翻倍。后来测试小姐姐跟我吐槽:“你们这订单模块,我测一次得花一下午,比我逛街还累。”

二、啥是流程编排?说白了就是 “给代码找个管家”
既然 if-else 这么坑,那有没有办法让代码 “变整齐”?答案就是流程编排。可能有些兄弟觉得 “流程编排” 这词儿听着挺玄乎,其实特好理解 —— 就像你去餐厅吃饭,后厨不会让一个厨师又买菜又切菜又炒菜又装盘,而是有专门的采购、切配、掌勺、摆盘师傅,各司其职,最后把菜端到你面前。流程编排就是给代码做 “分工”:把一个复杂的业务流程,拆成一个个独立的 “小步骤”(比如订单处理里的 “支付验证”“满减计算”“库存扣减”),然后规定这些步骤的执行顺序,让它们像流水线一样配合工作。

咱还是拿订单处理举例,用流程编排重构后,逻辑会变成这样:
第一步:获取订单基础信息(独立步骤)
第二步:判断订单类型(独立步骤,不同类型走不同分支)
第三步:验证支付方式(独立步骤)
第四步:计算折扣(独立步骤,根据用户身份和金额)
第五步:扣减库存(独立步骤)
第六步:记录订单日志(独立步骤)

每个步骤都是一个 “小模块”,可以单独修改、测试、复用。比如要改折扣规则,只需要改 “计算折扣” 这个步骤,其他步骤完全不用动 —— 这就像你想换件衣服,不用把裤子、鞋子、袜子全换掉一样。可能有人会问:“这不就是把代码拆成方法吗?跟流程编排有啥区别”?区别大了!普通的方法拆分,还是需要你在主方法里用 if-else 调用各个方法,比如:
public void handleOrder(Order order) {
    getOrderInfo(order);
    if (order.getType() == OrderType.NORMAL) {
        checkNormalPay(order);
        calculateNormalDiscount(order);
    } else if (order.getType() == OrderType.GROUP) {
        checkGroupPay(order);
        calculateGroupDiscount(order);
    }
    deductStock(order);
    logOrder(order);
}
而流程编排是 “把步骤的执行顺序也交给框架管理”,你不用写 if-else 调用,只需要告诉框架 “第一步执行 A,第二步执行 B,第三步根据条件选 C 或 D”,剩下的事儿框架全帮你干了。就像你不用亲自指挥后厨的每个师傅,只需要告诉餐厅 “我要一份番茄炒蛋”,餐厅的流程体系会自动让采购买番茄鸡蛋、切配师傅切菜、掌勺师傅炒菜 —— 这才是流程编排的核心:把 “指挥逻辑” 和 “执行逻辑” 彻底分开。

三、Java 生态里的流程编排方案:从 “轻量级” 到 “重量级”,总有一款适合你
聊完概念,咱来点实在的 ——Java 里到底有哪些流程编排方案?该怎么选?我把常用的方案分成了三类:轻量级(自己用设计模式实现)、中量级(Spring 生态工具)、重量级(专业流程引擎)。咱一个个说,每个方案都带代码示例,保证你看完就能用。

方案一:轻量级 —— 用 “责任链 + 策略模式”,不用引入任何框架
如果你的业务流程不算特别复杂(比如只有 5-8 个步骤),又不想引入新框架,那用设计模式自己实现是最好的选择。这里推荐 “责任链模式 + 策略模式” 的组合,前者负责 “步骤顺序”,后者负责 “条件分支”。还是拿订单处理举例,咱一步步实现:

1. 第一步:定义 “流程节点” 接口(所有步骤都要实现这个接口)
先定义一个OrderProcessNode接口,里面只有一个process方法,每个步骤都是一个节点:
// 订单流程节点接口
public interface OrderProcessNode {
    // 处理订单流程,返回是否继续执行下一个节点
    boolean process(Order order);
}
返回boolean是为了控制流程:返回true表示继续执行下一个节点,返回false表示终止流程(比如支付验证失败,就不用执行后面的库存扣减了)。

2. 第二步:实现各个独立的流程节点
把之前嵌套在 if-else 里的逻辑,拆成一个个节点实现类:
① 获取订单信息节点
// 获取订单基础信息
public class OrderInfoNode implements OrderProcessNode {
    @Override
    public boolean process(Order order) {
        System.out.println("第一步:获取订单基础信息");
        // 模拟从数据库获取订单详情
        order.setProductName("iPhone 15");
        order.setAmount(5999.0);
        return true; // 继续执行下一个节点
    }
}
② 订单类型判断节点(策略模式在这里用)因为不同订单类型的处理逻辑不同,这里用策略模式,先定义订单类型处理器接口:
// 订单类型处理器接口(策略接口)
public interface OrderTypeHandler {
    void handle(Order order);
}
// 普通订单处理器(具体策略)
public class NormalOrderHandler implements OrderTypeHandler {
    @Override
    public void handle(Order order) {
        System.out.println("处理普通订单逻辑");
        order.setTypeDesc("普通订单,支持微信/支付宝支付");
    }
 // 堆代码 duidaima.com
// 团购订单处理器(具体策略)
public class GroupOrderHandler implements OrderTypeHandler {
    @Override
    public void handle(Order order) {
        System.out.println("处理团购订单逻辑");
        order.setTypeDesc("团购订单,需满3人成团");
    }
}
然后实现订单类型判断节点,根据订单类型选择对应的处理器:
// 订单类型判断节点
public class OrderTypeNode implements OrderProcessNode {
    // 策略工厂,根据订单类型获取对应的处理器
    private Map<OrderType, OrderTypeHandler> typeHandlerMap;
    // 构造方法初始化策略工厂
    public OrderTypeNode() {
        typeHandlerMap = new HashMap<>();
        typeHandlerMap.put(OrderType.NORMAL, new NormalOrderHandler());
        typeHandlerMap.put(OrderType.GROUP, new GroupOrderHandler());
    }
    @Override
    public boolean process(Order order) {
        System.out.println("第二步:判断订单类型");
        // 根据订单类型获取处理器,执行对应逻辑
        OrderTypeHandler handler = typeHandlerMap.get(order.getType());
        if (handler == null) {
            System.out.println("未知订单类型,终止流程");
            return false; // 终止流程
        }
        handler.handle(order);
        return true; // 继续执行下一个节点
    }
}
③ 支付验证节点
// 支付验证节点
public class PayCheckNode implements OrderProcessNode {
    @Override
    public boolean process(Order order) {
        System.out.println("第三步:验证支付方式");
        if (order.getPayType() == PayType.WECHAT || order.getPayType() == PayType.ALIPAY) {
            System.out.println("支付方式合法:" + order.getPayType());
            return true;
        } else {
            System.out.println("不支持的支付方式:" + order.getPayType() + ",终止流程");
            return false;
        }
    }
}
④ 折扣计算节点
// 折扣计算节点
public class DiscountCalculateNode implements OrderProcessNode {
    @Override
    public boolean process(Order order) {
        System.out.println("第四步:计算订单折扣");
        double discount = 1.0;
        // 老用户折扣
        if (order.getUser().isOldUser()) {
            discount -= 0.1; // 老用户9折
            System.out.println("老用户享受9折优惠");
        }
        // 满减折扣
        if (order.getAmount() >= 5000) {
            discount -= 0.05; // 满5000再减5%
            System.out.println("满5000元再减5%");
        }
        // 防止折扣低于0.5
        order.setDiscount(Math.max(discount, 0.5));
        System.out.println("最终折扣:" + order.getDiscount());
        return true;
    }
}
⑤ 库存扣减节点
// 库存扣减节点
publicclass StockDeductNode implements OrderProcessNode {
    private StockService stockService = new StockService(); // 模拟库存服务

    @Override
    public boolean process(Order order) {
        System.out.println("第五步:扣减订单库存");
        boolean deductSuccess = stockService.deductStock(order.getProductId(), order.getQuantity());
        if (deductSuccess) {
            System.out.println("库存扣减成功");
            returntrue;
        } else {
            System.out.println("库存不足,终止流程");
            returnfalse;
        }
    }
}
⑥ 日志记录节点
// 日志记录节点
public class OrderLogNode implements OrderProcessNode {
    private LogService logService = new LogService(); // 模拟日志服务

    @Override
    public boolean process(Order order) {
        System.out.println("第六步:记录订单日志");
        logService.recordLog("订单" + order.getOrderId() + "处理完成,最终金额:" + order.getAmount() * order.getDiscount());
        return true;
    }
}
3. 第三步:构建责任链,串联所有节点
接下来需要一个 “流程管理器”,把这些节点按顺序串成一条责任链,然后执行流程:
// 订单流程管理器(责任链)
publicclassOrderProcessChain {
    // 用链表存储所有节点,保证执行顺序
    private LinkedList<OrderProcessNode> nodeList = new LinkedList<>();

    // 添加节点到链尾
    public void addNode(OrderProcessNode node) {
        nodeList.add(node);
    }

    // 执行流程:依次调用每个节点的process方法
    public void execute(Order order) {
        for (OrderProcessNode node : nodeList) {
            boolean continueNext = node.process(order);
            if (!continueNext) {
                System.out.println("流程在节点[" + node.getClass().getSimpleName() + "]终止");
                return;
            }
        }
        System.out.println("所有流程节点执行完成!");
    }
}
4. 第四步:测试流程执行效果
最后写个测试类,看看流程跑起来怎么样:
public classOrderProcessTest {
    public static void main(String[] args) {
        // 1. 创建订单对象
        Order order = new Order();
        order.setOrderId("ORDER_20250826_001");
        order.setType(OrderType.NORMAL); // 普通订单
        order.setPayType(PayType.WECHAT); // 微信支付
        order.setProductId("PROD_001");
        order.setQuantity(1);
        User user = new User();
        user.setOldUser(true); // 老用户
        order.setUser(user);

        // 2. 构建流程链,按顺序添加节点
        OrderProcessChain chain = new OrderProcessChain();
        chain.addNode(new OrderInfoNode());
        chain.addNode(new OrderTypeNode());
        chain.addNode(new PayCheckNode());
        chain.addNode(new DiscountCalculateNode());
        chain.addNode(new StockDeductNode());
        chain.addNode(new OrderLogNode());

        // 3. 执行流程
        System.out.println("开始处理订单:" + order.getOrderId());
        chain.execute(order);
    }
}
运行结果如下:
开始处理订单:ORDER_20250826_001
第一步:获取订单基础信息
第二步:判断订单类型
处理普通订单逻辑
第三步:验证支付方式
支付方式合法:WECHAT
第四步:计算订单折扣
老用户享受9折优惠
满5000元再减5%
最终折扣:0.85
第五步:扣减订单库存
库存扣减成功
第六步:记录订单日志
所有流程节点执行完成!
你看,现在要加新规则,比如 “新用户首单支付宝支付减 200”,只需要新建一个NewUserAlipayDiscountNode,然后在流程链里加个节点就行:
// 新用户支付宝首单折扣节点
publicclass NewUserAlipayDiscountNode implements OrderProcessNode {
    @Override
    public boolean process(Order order) {
        System.out.println("新增步骤:新用户支付宝首单折扣");
        if (!order.getUser().isOldUser() && order.getPayType() == PayType.ALIPAY && order.isFirstOrder()) {
            order.setAmount(order.getAmount() - 200);
            System.out.println("新用户首单支付宝支付,立减200元,优惠后金额:" + order.getAmount());
        }
        returntrue;
    }
}

// 构建流程链时添加这个节点
chain.addNode(new NewUserAlipayDiscountNode()); // 加在折扣计算节点前面
完全不用动原来的任何代码,这就是 “插拔式” 开发的爽快感!

方案二:中量级 —— 用 Spring StateMachine,搞定 “状态流转” 类业务
如果你的业务里有很多 “状态变化” 的逻辑(比如订单状态:待支付→已支付→待发货→已发货→已完成),用上面的责任链模式虽然能实现,但状态管理会比较麻烦。这时候就该 Spring StateMachine 登场了 —— 它是 Spring 生态里专门处理 “状态机” 的工具,能帮你把复杂的状态流转逻辑变得清晰。
咱还是拿订单状态流转举例,比如订单有以下状态:
待支付(WAIT_PAY)
已支付(PAID)
待发货(WAIT_SHIP)
已发货(SHIPPED)
已完成(COMPLETED)
已取消(CANCELED)

状态之间的流转规则:
待支付 → 已支付(用户付款)
待支付 → 已取消(用户取消订单)
已支付 → 待发货(商家确认收款)
已支付 → 已取消(退款)
待发货 → 已发货(商家发货)
已发货 → 已完成(用户确认收货)
如果用 if-else 写,会是这样:
public void changeOrderStatus(Order order, String event) {
    if (order.getStatus() == OrderStatus.WAIT_PAY) {
        if ("PAY".equals(event)) {
            order.setStatus(OrderStatus.PAID);
        } elseif ("CANCEL".equals(event)) {
            order.setStatus(OrderStatus.CANCELED);
        }
    } elseif (order.getStatus() == OrderStatus.PAID) {
        if ("CONFIRM".equals(event)) {
            order.setStatus(OrderStatus.WAIT_SHIP);
        } elseif ("REFUND".equals(event)) {
            order.setStatus(OrderStatus.CANCELED);
        }
    } elseif (order.getStatus() == OrderStatus.WAIT_SHIP) {
        if ("SHIP".equals(event)) {
            order.setStatus(OrderStatus.SHIPPED);
        }
    }
    // 还有更多状态判断...
}
用 Spring StateMachine 重构后,代码会清爽很多。

1. 第一步:引入依赖
在 Spring Boot 项目的 pom.xml 里加依赖:
<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>3.2.0</version>
</dependency>
2. 第二步:定义订单状态和事件
先把订单状态和触发状态变化的事件定义成枚举:
// 订单状态枚举
publicenum OrderStatus {
    WAIT_PAY("待支付"),
    PAID("已支付"),
    WAIT_SHIP("待发货"),
    SHIPPED("已发货"),
    COMPLETED("已完成"),
    CANCELED("已取消");

    private final String desc;
    OrderStatus(String desc) {
        this.desc = desc;
    }
}

// 订单事件枚举(触发状态变化的动作)
publicenum OrderEvent {
    PAY("用户付款"),
    CANCEL("用户取消"),
    CONFIRM("商家确认收款"),
    REFUND("退款"),
    SHIP("商家发货"),
    CONFIRM_RECEIVE("用户确认收货");

    private final String desc;
    OrderEvent(String desc) {
        this.desc = desc;
    }
}
3. 第三步:配置状态机
创建一个配置类,定义状态机的状态、事件和流转规则:
@Configuration
@EnableStateMachineFactory// 启用状态机工厂,方便创建多个状态机实例
publicclass OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderEvent> {

    // 配置状态机的初始状态和所有状态
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvent> states) throws Exception {
        states
            .withStates()
            .initial(OrderStatus.WAIT_PAY) // 初始状态:待支付
            .states(EnumSet.allOf(OrderStatus.class)); // 所有状态
    }

    // 配置状态流转规则(核心)
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) throws Exception {
        transitions
            // 1. 待支付 → 已支付:触发事件PAY
            .withExternal()
            .source(OrderStatus.WAIT_PAY)
            .target(OrderStatus.PAID)
            .event(OrderEvent.PAY)
            .and()
            // 2. 待支付 → 已取消:触发事件CANCEL
            .withExternal()
            .source(OrderStatus.WAIT_PAY)
            .target(OrderStatus.CANCELED)
            .event(OrderEvent.CANCEL)
            .and()
            // 3. 已支付 → 待发货:触发事件CONFIRM
            .withExternal()
            .source(OrderStatus.PAID)
            .target(OrderStatus.WAIT_SHIP)
            .event(OrderEvent.CONFIRM)
            .and()
            // 4. 已支付 → 已取消:触发事件REFUND
            .withExternal()
            .source(OrderStatus.PAID)
            .target(OrderStatus.CANCELED)
            .event(OrderEvent.REFUND)
            .and()
            // 5. 待发货 → 已发货:触发事件SHIP
            .withExternal()
            .source(OrderStatus.WAIT_SHIP)
            .target(OrderStatus.SHIPPED)
            .event(OrderEvent.SHIP)
            .and()
            // 6. 已发货 → 已完成:触发事件CONFIRM_RECEIVE
            .withExternal()
            .source(OrderStatus.SHIPPED)
            .target(OrderStatus.COMPLETED)
            .event(OrderEvent.CONFIRM_RECEIVE);
    }

    // 配置状态机监听器,监听状态变化事件
    @Bean
    public StateMachineListener<OrderStatus, OrderEvent> orderStateListener() {
        returnnew StateMachineListenerAdapter<OrderStatus, OrderEvent>() {
            @Override
            public void stateChanged(State<OrderStatus, OrderEvent> from, State<OrderStatus, OrderEvent> to) {
                System.out.println("订单状态变化:" + (from == null ? "初始状态" : from.getId().getDesc()) 
                    + " → " + to.getId().getDesc());
            }

            @Override
            public void eventNotAccepted(Message<OrderEvent> event) {
                System.out.println("不支持的事件:" + event.getPayload().getDesc() 
                    + ",当前订单状态可能不允许此操作");
            }
        };
    }

    // 注册监听器
    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderEvent> config) throws Exception {
        config
            .withConfiguration()
            .listener(orderStateListener());
    }
}
4. 第四步:创建订单状态服务
写一个服务类,封装状态机的使用,方便业务层调用:
@Service
publicclassOrderStateService {

    @Autowired
    private StateMachineFactory<OrderStatus, OrderEvent> stateMachineFactory;

    // 线程安全:每个订单用一个独立的状态机实例
    private Map<String, StateMachine<OrderStatus, OrderEvent>> orderStateMachineMap = new ConcurrentHashMap<>();

    // 初始化订单状态机(订单创建时调用)
    public void initOrderStateMachine(String orderId) {
        StateMachine<OrderStatus, OrderEvent> stateMachine = stateMachineFactory.getStateMachine();
        // 设置订单ID作为状态机的ID,方便后续关联
        stateMachine.getExtendedState().getVariables().put("orderId", orderId);
        orderStateMachineMap.put(orderId, stateMachine);
        System.out.println("订单[" + orderId + "]状态机初始化完成,初始状态:" + stateMachine.getState().getId().getDesc());
    }

    // 触发订单状态变化(核心方法)
    public boolean sendEvent(String orderId, OrderEvent event) {
        StateMachine<OrderStatus, OrderEvent> stateMachine = orderStateMachineMap.get(orderId);
        if (stateMachine == null) {
            System.out.println("订单[" + orderId + "]状态机未初始化");
            returnfalse;
        }
        // 发送事件,触发状态变化
        return stateMachine.sendEvent(event);
    }

    // 获取订单当前状态
    public OrderStatus getCurrentState(String orderId) {
        StateMachine<OrderStatus, OrderEvent> stateMachine = orderStateMachineMap.get(orderId);
        if (stateMachine == null) {
            returnnull;
        }
        return stateMachine.getState().getId();
    }
}
5. 第五步:测试状态流转
写个测试类,模拟订单状态变化的整个过程:
@SpringBootTest
publicclassOrderStateMachineTest {

    @Autowired
    private OrderStateService orderStateService;

    @Test
    public void testOrderStateFlow() {
        String orderId = "ORDER_20250826_002";

        // 1. 初始化订单状态机
        orderStateService.initOrderStateMachine(orderId);

        // 2. 触发"用户付款"事件:待支付→已支付
        boolean paySuccess = orderStateService.sendEvent(orderId, OrderEvent.PAY);
        System.out.println("触发用户付款事件:" + (paySuccess ? "成功" : "失败"));
        System.out.println("当前订单状态:" + orderStateService.getCurrentState(orderId).getDesc() + "\n");

        // 3. 触发"商家确认收款"事件:已支付→待发货
        boolean confirmSuccess = orderStateService.sendEvent(orderId, OrderEvent.CONFIRM);
        System.out.println("触发商家确认收款事件:" + (confirmSuccess ? "成功" : "失败"));
        System.out.println("当前订单状态:" + orderStateService.getCurrentState(orderId).getDesc() + "\n");

        // 4. 触发"商家发货"事件:待发货→已发货
        boolean shipSuccess = orderStateService.sendEvent(orderId, OrderEvent.SHIP);
        System.out.println("触发商家发货事件:" + (shipSuccess ? "成功" : "失败"));
        System.out.println("当前订单状态:" + orderStateService.getCurrentState(orderId).getDesc() + "\n");

        // 5. 触发"用户确认收货"事件:已发货→已完成
        boolean confirmReceiveSuccess = orderStateService.sendEvent(orderId, OrderEvent.CONFIRM_RECEIVE);
        System.out.println("触发用户确认收货事件:" + (confirmReceiveSuccess ? "成功" : "失败"));
        System.out.println("当前订单状态:" + orderStateService.getCurrentState(orderId).getDesc() + "\n");

        // 6. 尝试触发"退款"事件(已完成状态不支持退款,会失败)
        boolean refundSuccess = orderStateService.sendEvent(orderId, OrderEvent.REFUND);
        System.out.println("触发退款事件:" + (refundSuccess ? "成功" : "失败"));
        System.out.println("当前订单状态:" + orderStateService.getCurrentState(orderId).getDesc());
    }
}
运行结果如下:
订单[ORDER_20250826_002]状态机初始化完成,初始状态:待支付
订单状态变化:初始状态 → 待支付
触发用户付款事件:成功
订单状态变化:待支付 → 已支付
当前订单状态:已支付
触发商家确认收款事件:成功
订单状态变化:已支付 → 待发货
当前订单状态:待发货
触发商家发货事件:成功
订单状态变化:待发货 → 已发货
当前订单状态:已发货
触发用户确认收货事件:成功
订单状态变化:已发货 → 已完成
当前订单状态:已完成
不支持的事件:退款,当前订单状态可能不允许此操作
触发退款事件:失败

当前订单状态:已完成


你看,所有状态流转规则都集中在配置类里,不用写一行 if-else。如果要加新的状态流转(比如 “已发货→已取消”,用户拒收退款),只需要在transitions配置里加一段:
.withExternal()
.source(OrderStatus.SHIPPED)
.target(OrderStatus.CANCELED)
.event(OrderEvent.REJECT_REFUND); // 新增“拒收退款”事件
是不是比改 if-else 舒服多了?

方案三:重量级 —— 用 Flowable/Camunda,应对 “可视化 + 复杂流程”
如果你的业务流程非常复杂(比如 OA 审批流程、电商售后流程),需要产品经理能可视化编辑流程,或者需要支持流程暂停、重试、回滚、定时任务等高级功能,那轻量级和中量级方案就不够用了,这时候就得上专业的流程引擎 ——Flowable 和 Camunda 是目前 Java 生态里最火的两款。这俩引擎都基于 BPMN 2.0 标准(业务流程建模与 notation),支持用画图的方式定义流程,产品经理用 Flowable Modeler 或 Camunda Modeler 画个流程图,开发直接把图导入项目就能用,不用手写流程逻辑。

咱以 Flowable 为例,用 “电商售后退款流程” 来演示,流程如下:
用户提交退款申请(需填写退款原因和金额)
系统自动验证退款金额是否合理(≤订单金额)
验证通过→商家审核;验证失败→驳回用户申请
商家审核:通过→财务审核;不通过→驳回用户申请
财务审核:通过→执行退款;不通过→驳回用户申请
执行退款后,发送短信通知用户

1. 第一步:引入依赖
Spring Boot 项目加 Flowable 依赖:
<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter</artifactId>
    <version>7.0.0.M2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>
这里用 H2 内存数据库,方便测试。

2. 第二步:画 BPMN 流程图
用 Flowable Modeler(官网可下载)画流程图,保存为after_sales_refund.bpmn20.xml,放在src/main/resources/processes目录下(Flowable 会自动扫描这个目录的流程文件)。流程图的 XML 内容如下(你也可以直接复制用,或用 Modeler 可视化编辑):
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd"
             xmlns:flowable="http://flowable.org/bpmn"
             id="Definitions_1"
             targetNamespace="http://flowable.org/bpmn">

    <process id="afterSalesRefundProcess" name="电商售后退款流程" isExecutable="true">
        <!-- 开始事件:用户提交退款申请 -->
        <startEvent id="startEvent1" name="用户提交退款申请">
            <extensionElements>
                <!-- 定义流程变量:订单ID、退款金额、退款原因、用户ID -->
                <flowable:formProperty id="orderId" name="订单ID" type="string" required="true"/>
                <flowable:formProperty id="refundAmount" name="退款金额" type="double" required="true"/>
                <flowable:formProperty id="refundReason" name="退款原因" type="string" required="true"/>
                <flowable:formProperty id="userId" name="用户ID" type="string" required="true"/>
            </extensionElements>
        </startEvent>

        <!-- 服务任务:系统验证退款金额 -->
        <serviceTask id="validateRefundAmountTask" name="验证退款金额" flowable:delegateExpression="${validateRefundAmountDelegate}"/>

        <!-- 排他网关:验证结果判断 -->
        <exclusiveGateway id="validateGateway" name="验证结果"/>
        <sequenceFlow id="flow1" sourceRef="startEvent1" targetRef="validateRefundAmountTask"/>
        <sequenceFlow id="flow2" sourceRef="validateRefundAmountTask" targetRef="validateGateway"/>

        <!-- 服务任务:驳回用户申请 -->
        <serviceTask id="rejectTask" name="驳回用户申请" flowable:delegateExpression="${rejectRefundDelegate}"/>
        <!-- 结束事件:流程结束 -->
        <endEvent id="endEvent1" name="流程结束"/>
        <sequenceFlow id="flow3" sourceRef="rejectTask" targetRef="endEvent1"/>

        <!-- 用户任务:商家审核 -->
        <userTask id="merchantAuditTask" name="商家审核" flowable:assignee="merchant">
            <extensionElements>
                <!-- 商家审核结果:通过/不通过 -->
                <flowable:formProperty id="merchantAuditResult" name="审核结果" type="enum" required="true">
                    <flowable:value id="pass" name="通过"/>
                    <flowable:value id="reject" name="不通过"/>
                </flowable:formProperty>
                <flowable:formProperty id="merchantAuditComment" name="审核意见" type="string"/>
            </extensionElements>
        </userTask>
        <!-- 排他网关:商家审核结果判断 -->
        <exclusiveGateway id="merchantAuditGateway" name="商家审核结果"/>
        <sequenceFlow id="flow4" sourceRef="validateGateway" targetRef="merchantAuditTask">
            <!-- 条件:验证通过 -->
            <conditionExpression xsi:type="tFormalExpression">#{validateResult == 'pass'}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow5" sourceRef="validateGateway" targetRef="rejectTask">
            <!-- 条件:验证失败 -->
            <conditionExpression xsi:type="tFormalExpression">#{validateResult == 'reject'}</conditionExpression>
        </sequenceFlow>

        <!-- 用户任务:财务审核 -->
        <userTask id="financeAuditTask" name="财务审核" flowable:assignee="finance">
            <extensionElements>
                <!-- 财务审核结果:通过/不通过 -->
                <flowable:formProperty id="financeAuditResult" name="审核结果" type="enum" required="true">
                    <flowable:value id="pass" name="通过"/>
                    <flowable:value id="reject" name="不通过"/>
                </flowable:formProperty>
                <flowable:formProperty id="financeAuditComment" name="审核意见" type="string"/>
            </extensionElements>
        </userTask>
        <sequenceFlow id="flow6" sourceRef="merchantAuditTask" targetRef="merchantAuditGateway"/>
        <sequenceFlow id="flow7" sourceRef="merchantAuditGateway" targetRef="financeAuditTask">
            <!-- 条件:商家审核通过 -->
            <conditionExpression xsi:type="tFormalExpression">#{merchantAuditResult == 'pass'}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow8" sourceRef="merchantAuditGateway" targetRef="rejectTask">
            <!-- 条件:商家审核不通过 -->
            <conditionExpression xsi:type="tFormalExpression">#{merchantAuditResult == 'reject'}</conditionExpression>
        </sequenceFlow>

        <!-- 排他网关:财务审核结果判断 -->
        <exclusiveGateway id="financeAuditGateway" name="财务审核结果"/>
        <!-- 服务任务:执行退款 -->
        <serviceTask id="executeRefundTask" name="执行退款" flowable:delegateExpression="${executeRefundDelegate}"/>
        <!-- 服务任务:发送退款通知 -->
        <serviceTask id="sendNotifyTask" name="发送退款通知" flowable:delegateExpression="${sendRefundNotifyDelegate}"/>

        <sequenceFlow id="flow9" sourceRef="financeAuditTask" targetRef="financeAuditGateway"/>
        <sequenceFlow id="flow10" sourceRef="financeAuditGateway" targetRef="executeRefundTask">
            <!-- 条件:财务审核通过 -->
            <conditionExpression xsi:type="tFormalExpression">#{financeAuditResult == 'pass'}</conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow11" sourceRef="financeAuditGateway" targetRef="rejectTask">
            <!-- 条件:财务审核不通过 -->
            <conditionExpression xsi:type="tFormalExpression">#{financeAuditResult == 'reject'}</conditionExpression>
        </sequenceFlow>

        <sequenceFlow id="flow12" sourceRef="executeRefundTask" targetRef="sendNotifyTask"/>
        <sequenceFlow id="flow13" sourceRef="sendNotifyTask" targetRef="endEvent1"/>
    </process>
</definitions>
3. 第三步:实现流程任务的业务逻辑
Flowable 里的serviceTask需要用Delegate类实现具体业务逻辑,这里实现 5 个任务的 Delegate:
① 验证退款金额 Delegate
@Component("validateRefundAmountDelegate")
publicclass ValidateRefundAmountDelegate implements JavaDelegate {

    // 模拟订单服务,获取订单金额
    @Autowired
    private OrderService orderService;

    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("开始验证退款金额");
        // 获取流程变量
        String orderId = (String) execution.getVariable("orderId");
        Double refundAmount = (Double) execution.getVariable("refundAmount");

        // 从订单服务获取订单金额
        Double orderAmount = orderService.getOrderAmount(orderId);
        System.out.println("订单[" + orderId + "]金额:" + orderAmount + ",申请退款金额:" + refundAmount);

        // 验证逻辑:退款金额≤订单金额
        if (refundAmount <= orderAmount && refundAmount > 0) {
            execution.setVariable("validateResult", "pass");
            System.out.println("退款金额验证通过");
        } else {
            execution.setVariable("validateResult", "reject");
            execution.setVariable("rejectReason", "退款金额不合法(需大于0且≤订单金额)");
            System.out.println("退款金额验证失败:" + execution.getVariable("rejectReason"));
        }
    }
}
② 驳回退款 Delegate
@Component("rejectRefundDelegate")
publicclass RejectRefundDelegate implements JavaDelegate {

    @Autowired
    private RefundService refundService;

    @Override
    publicvoid execute(DelegateExecution execution) {
        System.out.println("开始处理驳回退款申请");
        String orderId = (String) execution.getVariable("orderId");
        String rejectReason = (String) execution.getVariable("rejectReason");

        // 更新退款单状态为“已驳回”
        refundService.updateRefundStatus(orderId, RefundStatus.REJECTED, rejectReason);
        System.out.println("订单[" + orderId + "]退款申请已驳回,原因:" + rejectReason);
    }
}
③ 执行退款 Delegate
@Component("executeRefundDelegate")
publicclass ExecuteRefundDelegate implements JavaDelegate {

    @Autowired
    private RefundService refundService;

    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("开始执行退款操作");
        String orderId = (String) execution.getVariable("orderId");
        Double refundAmount = (Double) execution.getVariable("refundAmount");

        // 调用支付网关执行退款
        boolean refundSuccess = refundService.executeRefund(orderId, refundAmount);
        if (refundSuccess) {
            // 更新退款单状态为“已退款”
            refundService.updateRefundStatus(orderId, RefundStatus.REFUNDED, "退款成功");
            execution.setVariable("refundResult", "success");
            System.out.println("订单[" + orderId + "]退款执行成功,金额:" + refundAmount);
        } else {
            // 更新退款单状态为“退款失败”
            refundService.updateRefundStatus(orderId, RefundStatus.REFUND_FAILED, "支付网关退款失败");
            execution.setVariable("refundResult", "fail");
            System.out.println("订单[" + orderId + "]退款执行失败");
        }
    }
}
④ 发送退款通知 Delegate
@Component("sendRefundNotifyDelegate")
publicclass SendRefundNotifyDelegate implements JavaDelegate {

    @Autowired
    private SmsService smsService;

    @Override
    publicvoid execute(DelegateExecution execution) {
        System.out.println("开始发送退款通知");
        String userId = (String) execution.getVariable("userId");
        String orderId = (String) execution.getVariable("orderId");
        Double refundAmount = (Double) execution.getVariable("refundAmount");

        // 获取用户手机号(模拟)
        String phone = smsService.getUserPhone(userId);
        // 发送短信通知
        String content = "【电商平台】您的订单" + orderId + "已成功退款" + refundAmount + "元,请注意查收。";
        smsService.sendSms(phone, content);
        System.out.println("已向用户[" + userId + "]的手机号[" + phone + "]发送退款通知:" + content);
    }
}
4. 第四步:写接口测试流程
创建 Controller,提供接口让前端调用,触发流程和处理审核:
@RestController
@RequestMapping("/refund")
publicclass RefundController {

    @Autowired
    private RuntimeService runtimeService; // Flowable的运行时服务,用于启动流程
    @Autowired
    private TaskService taskService; // Flowable的任务服务,用于处理用户任务(审核)

    // 1. 用户提交退款申请(启动流程)
    @PostMapping("/apply")
    publicString applyRefund(@RequestBody RefundApplyDTO applyDTO) {
        // 设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("orderId", applyDTO.getOrderId());
        variables.put("refundAmount", applyDTO.getRefundAmount());
        variables.put("refundReason", applyDTO.getRefundReason());
        variables.put("userId", applyDTO.getUserId());

        // 启动流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("afterSalesRefundProcess", variables);
        System.out.println("退款流程已启动,流程实例ID:" + processInstance.getId());
        return"退款申请提交成功,流程实例ID:" + processInstance.getId();
    }

    // 2. 商家审核退款申请
    @PostMapping("/merchant/audit")
    publicString merchantAudit(@RequestBody MerchantAuditDTO auditDTO) {
        // 根据流程实例ID和任务负责人(商家)查询任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(auditDTO.getProcessInstanceId())
                .taskAssignee("merchant") // 商家的用户ID
                .singleResult();

        if (task == null) {
            return"未找到待审核的任务";
        }

        // 设置审核结果变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("merchantAuditResult", auditDTO.getAuditResult()); // pass/reject
        variables.put("merchantAuditComment", auditDTO.getAuditComment());

        // 如果审核不通过,设置驳回原因
        if ("reject".equals(auditDTO.getAuditResult())) {
            variables.put("rejectReason", "商家审核不通过:" + auditDTO.getAuditComment());
        }

        // 完成任务(提交审核结果)
        taskService.complete(task.getId(), variables);
        return"商家审核已提交,结果:" + auditDTO.getAuditResult();
    }

    // 3. 财务审核退款申请
    @PostMapping("/finance/audit")
    publicString financeAudit(@RequestBody FinanceAuditDTO auditDTO) {
        // 根据流程实例ID和任务负责人(财务)查询任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(auditDTO.getProcessInstanceId())
                .taskAssignee("finance") // 财务的用户ID
                .singleResult();

        if (task == null) {
            return"未找到待审核的任务";
        }

        // 设置审核结果变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("financeAuditResult", auditDTO.getAuditResult()); // pass/reject
        variables.put("financeAuditComment", auditDTO.getAuditComment());

        // 如果审核不通过,设置驳回原因
        if ("reject".equals(auditDTO.getAuditResult())) {
            variables.put("rejectReason", "财务审核不通过:" + auditDTO.getAuditComment());
        }

        // 完成任务(提交审核结果)
        taskService.complete(task.getId(), variables);
        return"财务审核已提交,结果:" + auditDTO.getAuditResult();
    }

    // 4. 查询流程状态
    @GetMapping("/status/{processInstanceId}")
    publicString getProcessStatus(@PathVariableString processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

        if (processInstance == null) {
            // 流程已结束,查询历史状态
            HistoricProcessInstance historicProcessInstance = runtimeService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult();
            return"流程已结束,结束时间:" + historicProcessInstance.getEndTime() + ",状态:" + historicProcessInstance.getState();
        } else {
            // 流程未结束,查询当前任务
            Task currentTask = taskService.createTaskQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult();
            String currentTaskName = currentTask != null ? currentTask.getName() : "无当前任务";
            return"流程运行中,当前状态:" + processInstance.getState() + ",当前任务:" + currentTaskName;
        }
    }
}
5. 第五步:测试流程完整运行
用 Postman 或 curl 调用接口,模拟整个退款流程:
① 提交退款申请
请求 URL:http://localhost:8080/refund/apply
请求体:
{
    "orderId": "ORDER_20250826_003",
    "refundAmount": 100.0,
    "refundReason": "商品质量问题",
    "userId": "USER_001"
}
响应:退款申请提交成功,流程实例ID:12501
② 商家审核通过
请求 URL:http://localhost:8080/refund/merchant/audit
请求体:
{
    "processInstanceId": "12501",
    "auditResult": "pass",
    "auditComment": "同意退款"
}
响应:商家审核已提交,结果:pass
③ 财务审核通过
请求 URL:http://localhost:8080/refund/finance/audit
请求体:
{
    "processInstanceId": "12501",
    "auditResult": "pass",
    "auditComment": "同意退款,已安排打款"
}
响应:财务审核已提交,结果:pass
④ 查询流程状态
请求 URL:http://localhost:8080/refund/status/12501
响应:流程已结束,结束时间:2025-08-26T15:30:45.123+08:00,状态:COMPLETED
后台日志会打印整个流程的执行过程,从验证金额到商家审核、财务审核、执行退款、发送通知,一步不差。如果产品经理想改流程(比如加个 “客服初审” 步骤),只需要在 BPMN 图里加个用户任务,不用改任何 Java 代码 —— 这就是流程引擎的强大之处。

四、流程编排不是 “银弹”,这些坑你得避开
讲了这么多流程编排的好处,不是说它能解决所有问题。就像你不会用大炮打蚊子一样,流程编排也有它的适用场景,用错了反而会增加复杂度。我总结了几个项目里踩过的坑,大家一定要注意:
1. 「过度设计」:简单业务用了复杂流程,纯属自找麻烦
有些兄弟刚学会流程编排,就不管什么业务都想用。比如一个简单的 “根据用户等级返回折扣” 的逻辑,用一行 if-else 就能搞定:
public double getDiscount(User user) {
    if (user.getLevel() == Level.VIP1) return 0.95;
    else if (user.getLevel() == Level.VIP2) return 0.9;
    else return 1.0;
}
结果非要用责任链模式,拆成Vip1DiscountNode、Vip2DiscountNode、NormalUserDiscountNode,还建个流程链 —— 这就是 “为了用技术而用技术”,反而增加了代码量和维护成本。记住:业务简单用 if-else,业务复杂用流程编排。判断标准很简单:如果你的 if-else 嵌套超过 3 层,或者业务规则经常变动,再考虑流程编排。

2. 「忽略异常处理」:流程断了没人管,线上出问题才慌
我之前重构订单流程时,忘了给 “库存扣减” 节点加异常处理,结果有次库存服务超时,流程卡在了库存扣减步骤,订单状态一直是 “待库存扣减”,用户付了钱却看不到订单状态更新,投诉了一大堆。
后来我在每个节点都加了异常重试和降级逻辑:
// 改进后的库存扣减节点
publicclass StockDeductNode implements OrderProcessNode {
    private StockService stockService = new StockService();
    private RetryTemplate retryTemplate; // 重试模板

    public StockDeductNode() {
        // 初始化重试模板:重试3次,每次间隔1秒
        retryTemplate = new RetryTemplate();
        retryTemplate.setRetryPolicy(new SimpleRetryPolicy(3));
        retryTemplate.setBackOffPolicy(new FixedBackOffPolicy() {{
            setBackOffPeriod(1000);
        }});
    }

    @Override
    public boolean process(Order order) {
        try {
            // 重试3次库存扣减
            return retryTemplate.execute(context -> {
                boolean deductSuccess = stockService.deductStock(order.getProductId(), order.getQuantity());
                if (!deductSuccess) {
                    thrownew RuntimeException("库存扣减失败,重试中...");
                }
                System.out.println("库存扣减成功");
                returntrue;
            });
        } catch (Exception e) {
            // 重试失败后降级:记录日志,触发人工介入
            System.out.println("库存扣减失败(已重试3次),触发人工处理:" + e.getMessage());
            sendAlertToStaff(order); // 发送告警给运营人员
            returnfalse;
        }
    }
}
不管用哪种流程编排方案,都要考虑 “节点失败了怎么办”,是重试、降级还是终止流程,必须提前定义好。

3. 「流程可视化过度依赖」:把所有逻辑都画在图里,调试起来想死
用 Flowable/Camunda 的时候,有些团队喜欢把所有业务逻辑都用 BPMN 的网关和表达式实现,比如在条件表达式里写复杂的判断:
<sequenceFlow id="flow4" sourceRef="validateGateway" targetRef="merchantAuditTask">
    <conditionExpression xsi:type="tFormalExpression">
        #{validateResult == 'pass' && refundAmount > 100 && userLevel == 'VIP' && orderCreateTime > '2025-08-01'}
    </conditionExpression>
</sequenceFlow>
这种表达式写多了,调试起来特别麻烦 —— 流程走到这一步没按预期走,你得去看 BPMN 图里的表达式有没有写错,还得查流程变量的值,比看 Java 代码还费劲。正确的做法是:复杂逻辑写在 Delegate 类里,BPMN 图只负责流程走向。表达式只用来做简单的条件判断(比如#{validateResult == 'pass'}),这样调试的时候,直接看 Delegate 类的日志就行。

4. 「不考虑性能」:流程节点太多,响应时间变慢
流程编排本质上是把一个方法拆成多个方法执行,节点越多,方法调用次数越多,性能开销也越大。我之前见过一个流程有 20 多个节点,每个节点都要查数据库,结果整个流程执行下来要 5 秒多,用户直接吐槽 “比蜗牛还慢”。

后来我们做了优化:
合并相似节点:把 “查询用户信息” 和 “查询用户等级” 两个节点合并成一个,减少数据库查询次数
异步执行非关键节点:把 “记录日志”“发送通知” 这些不影响主流程的节点改成异步执行
缓存常用数据:把用户等级、商品价格这些高频访问的数据缓存起来,避免重复查询
优化后流程执行时间降到了 1 秒以内,用户体验明显提升。所以设计流程的时候,一定要考虑 “每个节点的执行时间”,别让流程变成 “性能瓶颈”。

五、总结:从 “if-else 地狱” 到 “流程编排天堂”,就差这一步
回顾一下这篇文章,咱从 if-else 的痛点说起,讲了流程编排的核心思想,还演示了三种不同量级的实现方案:
轻量级:责任链 + 策略模式,适合简单流程,不用引入框架
中量级:Spring StateMachine,适合状态流转类业务
重量级:Flowable/Camunda,适合复杂流程和可视化需求

最后还提醒了大家要避开的坑,希望能帮你彻底告别 if-else 的噩梦。其实流程编排不只是一种技术,更是一种 “分而治之” 的思维 —— 把复杂的问题拆成简单的小问题,再把小问题的解决方案按顺序组合起来。这种思维不仅能用于代码开发,在日常工作中也很有用,比如你写一篇技术文章,也可以拆成 “列大纲→写初稿→改内容→校对错” 这几个步骤,一步步来,效率会高很多。
用户评论