返回

Spring状态机:玩转状态管理,构建复杂业务系统

后端

Spring状态机:轻松管理复杂业务场景

在软件开发中,我们经常面临着对复杂业务场景进行建模和管理的挑战。例如,在线购物系统的订单处理流程涉及多个状态,如下单、付款、发货和收货。传统的管理方法容易导致代码复杂且难以维护。

状态模式 应运而生,它将状态封装成独立对象,提供统一的接口访问状态,实现状态的动态切换和管理。基于状态模式,Spring状态机 是一个强大的框架,为构建复杂业务系统提供了丰富的能力。

优点

  • 状态解耦: 将状态与业务逻辑分离,代码更清晰易维护。
  • 扩展性强: 添加新状态或事件时,仅需修改相应类,无需修改整个系统。
  • 支持持久化: 将状态机数据存储到持久化介质中,系统重启后可恢复状态。

入门指南

定义状态

状态可以是任何实体,如订单状态(下单、付款、发货、收货)。

定义事件

事件触发状态转换,如“付款”事件触发订单状态从“下单”到“付款”的转换。

定义动作

状态转换时执行的动作,如订单状态从“下单”到“付款”时执行“扣减库存”动作。

定义状态机

状态机由状态、事件和动作组成,使用Spring状态机API定义状态机。

@Configuration
public class OrderStateMachineConfig {

    @Bean
    public StateMachine<OrderStatus, OrderEvent> orderStateMachine() {
        // 定义状态
        EnumState<OrderStatus, OrderEvent> state = EnumState.builder(OrderStatus.class, OrderEvent.class)
                .initialState(OrderStatus.PLACED)
                .permit(OrderEvent.PAY, OrderStatus.PLACED, OrderStatus.PAID)
                .permit(OrderEvent.SHIP, OrderStatus.PAID, OrderStatus.SHIPPED)
                .permit(OrderEvent.RECEIVE, OrderStatus.SHIPPED, OrderStatus.RECEIVED)
                .build();

        // 定义状态机
        StateMachine<OrderStatus, OrderEvent> machine = new StateMachineBuilder<OrderStatus, OrderEvent>()
                .configureStates()
                .withStates()
                .initial(OrderStatus.PLACED)
                .state(OrderStatus.PAID)
                .state(OrderStatus.SHIPPED)
                .state(OrderStatus.RECEIVED)
                .and()
                .withExternal()
                .state(OrderStatus.CANCELLED)
                .and()
                .withStates()
                .end(OrderStatus.COMPLETED)
                .and()
                .withConfiguration()
                .stateMachineErrorCallbacks(new ErrorCallbacks())
                .configureTransitions()
                .withExternal()
                .source(OrderStatus.PLACED)
                .target(OrderStatus.CANCELLED)
                .event(OrderEvent.CANCEL)
                .and()
                .withExternal()
                .source(OrderStatus.PAID)
                .target(OrderStatus.CANCELLED)
                .event(OrderEvent.CANCEL)
                .and()
                .withExternal()
                .source(OrderStatus.SHIPPED)
                .target(OrderStatus.CANCELLED)
                .event(OrderEvent.CANCEL)
                .and()
                .build(state);

        return machine;
    }
}

进阶功能

条件转移

在状态转换时添加条件判断,如订单状态从“下单”到“付款”仅当支付成功时才进行转换。

@Configuration
public class OrderStateMachineConditionalConfig {

    @Bean
    public StateMachine<OrderStatus, OrderEvent> orderStateMachine() {
        // ... 同上 ...

        return machine
                // 条件转移
                .configureTransitions()
                .withExternal()
                .source(OrderStatus.PLACED)
                .target(OrderStatus.PAID)
                .event(OrderEvent.PAY)
                .guard(new IsPaymentSuccessGuard())
                .and()
                .build(state);
    }

    // 支付成功守卫
    private static class IsPaymentSuccessGuard implements Guard<OrderStatus, OrderEvent> {

        @Override
        public boolean evaluate(StateContext<OrderStatus, OrderEvent> context) {
            // 从上下文获取订单并检查是否支付成功
            Order order = (Order) context.getMessageHeader(OrderHeaders.ORDER);
            return order.isPaymentSuccess();
        }
    }
}

持久化

将状态机数据存储到持久化介质中,在系统重启后恢复状态。

@Configuration
public class OrderStateMachinePersistenceConfig {

    @Bean
    public StateMachine<OrderStatus, OrderEvent> orderStateMachine() {
        // ... 同上 ...

        return machine
                .configureStateMachineFactory(stateMachineFactory)
                .build(state);
    }

    // 持久化状态机工厂
    private static class OrderStateMachineFactory implements StateMachineFactory<OrderStatus, OrderEvent> {

        private final OrderRepository orderRepository;

        public OrderStateMachineFactory(OrderRepository orderRepository) {
            this.orderRepository = orderRepository;
        }

        @Override
        public StateMachine<OrderStatus, OrderEvent> build(
                State<OrderStatus, OrderEvent> initial, List<State<OrderStatus, OrderEvent>> states,
                List<Transition<OrderStatus, OrderEvent>> transitions, List<Junction<OrderStatus, OrderEvent>> junctions,
                MachineListener<OrderStatus, OrderEvent>... listeners) {

            // 加载订单状态
            OrderStatus orderStatus = orderRepository.findOrderStatus(orderId);

            // 构建状态机
            StateMachine<OrderStatus, OrderEvent> machine = new StateMachine<>(initial, states, transitions, junctions, listeners);

            // 设置状态机持久化
            machine.getStateMachinePersist()
                    .setContextObjectSerializer(new OrderContextObjectSerializer())
                    .setPersister(new OrderStatePersister(orderRepository));

            return machine;
        }
    }
}

结论

Spring状态机是一个强大的工具,可以轻松管理复杂业务场景,保持代码简洁和易于维护。它提供了丰富的功能,包括状态解耦、扩展性、条件转移、持久化和集成,使它成为构建复杂业务系统的理想选择。

常见问题解答

1. 什么是状态模式?

状态模式将状态封装成独立对象,提供统一的接口访问状态,实现状态的动态切换和管理。

2. Spring状态机有哪些优势?

易于使用、可扩展性强、支持持久化。

3. 如何使用Spring状态机定义状态机?

使用StateMachineBuilder定义状态、事件、动作和条件转移。

4. 如何在状态转换时执行动作?

State对象中定义EntryActionsExitActions

5. 如何持久化状态机?

配置StateMachinePersist并实现Persister接口。