Mastering Spring State Machine: Efficient Order Workflow Management

This article explains how to use Spring State Machine to model and control order lifecycle transitions in an e‑commerce system, covering core concepts, configuration, listeners, service integration, controller endpoints, and visual results for robust backend state management.

Lobster Programming
Lobster Programming
Lobster Programming
Mastering Spring State Machine: Efficient Order Workflow Management

In everyday development, many scenarios involve managing state flows, such as order processing where an order moves through creation, payment, delivery, and completion or cancellation. Spring State Machine provides a framework to efficiently handle these state transitions and extend behavior.

1. Understanding Spring State Machine

Spring State Machine (Spring State Machine) manages the relationship between states, events, and transitions, simplifying code for objects that change state based on events. It makes the code clearer and more maintainable.

Think of an elevator with states like stopped, moving, door opening, and door closing. Pressing a floor button (event) triggers the elevator to move, stop, and open doors. Spring State Machine works similarly with a finite set of states, transitions, and actions.

State : defines possible states (e.g., stopped, moving, door open).

Event : triggers a transition (e.g., button press).

Transition : defines how a specific event moves the system from one state to another.

Action : optional logic executed before or after a transition (e.g., update DB, send email).

2. Practical Example: Order State Management

Using a typical e‑commerce order flow, we demonstrate how Spring State Machine can efficiently manage order states. The diagram below shows the order state flow.

The project’s basic structure is illustrated below.

(1) Add Spring State Machine Dependency

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-starter</artifactId>
    <version>2.5.1</version>
</dependency>

(2) Define Order States

@Getter
@AllArgsConstructor
public enum OrderStatusEnum {
    WAIT_PAY(0, "待支付"),
    WAIT_DELIVER(1, "待发货"),
    WAIT_RECEIVE(2, "待收货"),
    RECEIVED(3, "已收货");
    private Integer code;
    private String msg;
}

(3) Define Order Events

@Getter
@AllArgsConstructor
public enum OrderStatusEventEnum {
    ORDER(1, "用户下单"),
    PAY(2, "用户支付"),
    DELIVER(3, "仓库发货"),
    RECEIVE(4, "用户收货");
    private final Integer code;
    private final String msg;
}

(4) Configure State Machine and Transitions

@Configurable
@EnableStateMachine(name ="orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusEventEnum> {

    /** Initialization */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusEventEnum> states) throws Exception {
        states.withStates()
                .initial(OrderStatusEnum.WAIT_PAY)   // initial state
                .states(EnumSet.allOf(OrderStatusEnum.class));   // all possible states
    }

    /** Configure transitions and events */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusEventEnum> transitions) throws Exception {
        transitions
                // payment event: WAIT_PAY -> WAIT_DELIVER
                .withExternal().source(OrderStatusEnum.WAIT_PAY).target(OrderStatusEnum.WAIT_DELIVER).event(OrderStatusEventEnum.PAY)
                .and()
                // delivery event: WAIT_DELIVER -> WAIT_RECEIVE
                .withExternal().source(OrderStatusEnum.WAIT_DELIVER).target(OrderStatusEnum.WAIT_RECEIVE).event(OrderStatusEventEnum.DELIVER)
                .and()
                // receive event: WAIT_RECEIVE -> RECEIVED
                .withExternal().source(OrderStatusEnum.WAIT_RECEIVE).target(OrderStatusEnum.RECEIVED).event(OrderStatusEventEnum.RECEIVE);
    }
}

(5) Define Listeners

@Slf4j
@Component
@WithStateMachine(name = "orderStateMachine")
public class OrderMachineListener {

    @OnTransition(source = "WAIT_PAY", target = "WAIT_DELIVER")
    public void pay(Message<OrderStatusEventEnum> message) {
        OrderEntity entity = message.getHeaders().get("order", OrderEntity.class);
        entity.setStatus(OrderStatusEnum.WAIT_DELIVER.getCode());
        System.out.println("orderMachine   WAIT_PAY-> WAIT_DELIVER");
    }

    @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")
    public void delivery(Message<OrderStatusEventEnum> message) {
        OrderEntity entity = message.getHeaders().get("order", OrderEntity.class);
        entity.setStatus(OrderStatusEnum.WAIT_DELIVER.getCode());
        System.out.println("orderMachine   WAIT_DELIVER-> WAIT_RECEIVE");
    }

    @OnTransition(source = "WAIT_RECEIVE", target = "RECEIVED")
    public void received(Message<OrderStatusEventEnum> message) {
        OrderEntity entity = message.getHeaders().get("order", OrderEntity.class);
        entity.setStatus(OrderStatusEnum.WAIT_DELIVER.getCode());
        System.out.println("orderMachine   WAIT_RECEIVE-> RECEIVED");
    }
}

(6) Trigger the State Machine

@Component
@Slf4j
public class OrderProcessorService {

    @Resource
    private StateMachine<OrderStatusEnum, OrderStatusEventEnum> orderStatusMachine;

    public Boolean process(OrderEntity order, OrderStatusEventEnum event) {
        orderStatusMachine.start();
        Message<OrderStatusEventEnum> message = MessageBuilder.withPayload(event)
                .setHeader("order", order)
                .build();
        return this.touchEvent(message);
    }

    private boolean touchEvent(Message<OrderStatusEventEnum> message) {
        OrderEntity order = (OrderEntity) message.getHeaders().get("order");
        System.out.println("订单的信息 orderId=" + (Objects.nonNull(order) ? order.getId() : "-"));
        return orderStatusMachine.sendEvent(message);
    }
}

(7) Test Controller

@RestController
@RequestMapping("/order")
public class OrderController {
    @Resource
    private OrderProcessorService orderProcessorService;

    @GetMapping("/pay")
    public String pay(Integer orderId) {
        OrderEntity order = new OrderEntity();
        order.setId(orderId);
        order.setStatus(OrderStatusEnum.WAIT_PAY.getCode());
        orderProcessorService.process(order, OrderStatusEventEnum.PAY);
        return "pay success";
    }

    @GetMapping("/deliver")
    public String deliver(Integer orderId) {
        OrderEntity order = new OrderEntity();
        order.setId(orderId);
        order.setStatus(OrderStatusEnum.WAIT_DELIVER.getCode());
        orderProcessorService.process(order, OrderStatusEventEnum.DELIVER);
        return "deliver success";
    }

    @GetMapping("/receive")
    public String receive(Integer orderId) {
        OrderEntity order = new OrderEntity();
        order.setId(orderId);
        order.setStatus(OrderStatusEnum.WAIT_RECEIVE.getCode());
        orderProcessorService.process(order, OrderStatusEventEnum.RECEIVE);
        return "receive success";
    }
}

(8) Execution Results

Payment state transition:

Console output shows the transition log.

Delivery state transition:

Console output confirms the delivery transition.

Receive state transition:

Console output confirms the final receipt transition.

In summary, Spring State Machine enables clear, maintainable, and extensible handling of complex business workflows with frequent state changes, making it suitable for high‑concurrency, low‑latency scenarios where a single process drives the flow.

Key takeaways:

If business processes are complex with many states and frequent transitions, Spring State Machine greatly improves code maintainability and extensibility.

Spring State Machine can be directly integrated into existing services and is ideal for high‑throughput, low‑latency use cases involving single‑process flow control.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

State ManagementSpring BootJava BackendOrder WorkflowSpring State Machine
Lobster Programming
Written by

Lobster Programming

Sharing insights on technical analysis and exchange, making life better through technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.