Mastering State Machines in Spring: From Design Patterns to Order Workflows
This article explains the State design pattern, compares Spring State Machine with alternatives, and provides a complete Java example that models order status transitions using Spring Statemachine, including code, configuration, listeners, services, and test execution.
1. State Pattern
State pattern is a behavioral design pattern that allows an object to change its behavior when its internal state changes. It encapsulates states in separate classes, making code clearer and easier to maintain.
Typical examples include traffic lights and order processing where objects have states like "ordered", "paid", "shipped", etc.
Class diagram of the state pattern:
The pattern defines three roles:
Context holds a reference to a State instance and delegates requests.
Abstract State defines the interface for state-specific behavior.
Concrete State implements the behavior for a specific state.
Example of a traffic‑light state machine using the pattern:
public abstract class MyState {
abstract void handler();
}
public class RedLightState extends MyState {
@Override
void handler() {
System.out.println("红灯停");
}
}
public class GreenLightState extends MyState {
@Override
void handler() {
System.out.println("绿灯行");
}
}
public class MyContext {
private MyState state;
public void setState(MyState state) { this.state = state; }
public void handler() { state.handler(); }
}
public class TestStateModel {
public static void main(String[] args) {
MyContext myContext = new MyContext();
RedLightState red = new RedLightState();
GreenLightState green = new GreenLightState();
myContext.setState(red);
myContext.handler(); // 红灯停
myContext.setState(green);
myContext.handler(); // 绿灯行
}
}The state pattern reduces if‑else logic, but it differs from the strategy pattern, which focuses on interchangeable algorithms rather than state transitions.
2. Spring State Machine
Spring State Machine is a framework implementation of the state pattern, providing a mathematical model of states and transitions. It helps structure complex workflows such as order processing.
Key elements of a state machine:
Current state – the starting point of a transition.
Trigger event – actions that cause a transition.
Response function – the rule that maps an event to the next state.
Target state – the destination of the transition.
Comparison between Spring State Machine and COLA State Machine shows Spring offers a richer ecosystem and more interfaces, while COLA is easier to customize.
3. Spring State Machine Implementation of Order State Flow
3.1 Environment Preparation
Add the Spring Statemachine dependency to a Spring Boot 2.2.1 project:
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>${springboot.version}</version>
</dependency>Define the order entity and enums for status and events:
public class Order {
private Long orderId;
private OrderStatusEnum orderStatus;
}
public enum OrderStatusEnum { WAIT_PAYMENT, WAIT_DELIVER, WAIT_RECEIVE, FINISH }
public enum OrderStatusChangeEventEnum { PAYED, DELIVERY, RECEIVED }3.2 Build the Order State Machine
@Configuration
@EnableStateMachine
public class OrderStatusMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEventEnum> {
@Override
public void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum> states) throws Exception {
states.withStates()
.initial(OrderStatusEnum.WAIT_PAYMENT)
.end(OrderStatusEnum.FINISH)
.states(EnumSet.allOf(OrderStatusEnum.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum> transitions) throws Exception {
transitions
.withExternal().source(OrderStatusEnum.WAIT_PAYMENT).target(OrderStatusEnum.WAIT_DELIVER).event(OrderStatusChangeEventEnum.PAYED).and()
.withExternal().source(OrderStatusEnum.WAIT_DELIVER).target(OrderStatusEnum.WAIT_RECEIVE).event(OrderStatusChangeEventEnum.DELIVERY).and()
.withExternal().source(OrderStatusEnum.WAIT_RECEIVE).target(OrderStatusEnum.FINISH).event(OrderStatusChangeEventEnum.RECEIVED);
}
}3.3 State Machine Listener
@Component
@WithStateMachine
@Transactional
public class OrderStatusListener {
@OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER")
public boolean payTransition(Message message) {
Order order = (Order) message.getHeaders().get("order");
order.setOrderStatus(OrderStatusEnum.WAIT_DELIVER);
System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
return true;
}
@OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")
public boolean deliverTransition(Message message) {
Order order = (Order) message.getHeaders().get("order");
order.setOrderStatus(OrderStatusEnum.WAIT_RECEIVE);
System.out.println("发货,状态机反馈信息:" + message.getHeaders().toString());
return true;
}
@OnTransition(source = "WAIT_RECEIVE", target = "FINISH")
public boolean receiveTransition(Message message) {
Order order = (Order) message.getHeaders().get("order");
order.setOrderStatus(OrderStatusEnum.FINISH);
System.out.println("收货,状态机反馈信息:" + message.getHeaders().toString());
return true;
}
}3.4 Order Service
@Service
public class OrderServiceImpl implements OrderService {
@Resource
private StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;
private long id = 1L;
private Map<Long, Order> orders = Maps.newConcurrentMap();
public Order create() {
Order order = new Order();
order.setOrderStatus(OrderStatusEnum.WAIT_PAYMENT);
order.setOrderId(id++);
orders.put(order.getOrderId(), order);
System.out.println("订单创建成功:" + order.toString());
return order;
}
public Order pay(long id) {
Order order = orders.get(id);
System.out.println("尝试支付,订单号:" + id);
Message message = MessageBuilder.withPayload(OrderStatusChangeEventEnum.PAYED)
.setHeader("order", order).build();
if (!sendEvent(message)) {
System.out.println("支付失败, 状态异常,订单号:" + id);
}
return orders.get(id);
}
public Order deliver(long id) {
Order order = orders.get(id);
System.out.println("尝试发货,订单号:" + id);
Message message = MessageBuilder.withPayload(OrderStatusChangeEventEnum.DELIVERY)
.setHeader("order", order).build();
if (!sendEvent(message)) {
System.out.println("发货失败,状态异常,订单号:" + id);
}
return orders.get(id);
}
public Order receive(long id) {
Order order = orders.get(id);
System.out.println("尝试收货,订单号:" + id);
Message message = MessageBuilder.withPayload(OrderStatusChangeEventEnum.RECEIVED)
.setHeader("order", order).build();
if (!sendEvent(message)) {
System.out.println("收货失败,状态异常,订单号:" + id);
}
return orders.get(id);
}
private synchronized boolean sendEvent(Message<OrderStatusChangeEventEnum> message) {
boolean result = false;
try {
orderStateMachine.start();
result = orderStateMachine.sendEvent(message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (Objects.nonNull(message)) {
Order order = (Order) message.getHeaders().get("order");
if (Objects.nonNull(order) && Objects.equals(order.getOrderStatus(), OrderStatusEnum.FINISH)) {
orderStateMachine.stop();
}
}
}
return result;
}
public Map<Long, Order> getOrders() { return orders; }
}3.5 Test Entry
@RestController
public class OrderController {
@Resource
private OrderService orderService;
@RequestMapping("/testOrderStatusChange")
public String testOrderStatusChange() {
orderService.create();
orderService.create();
orderService.pay(1L);
orderService.deliver(1L);
orderService.receive(1L);
orderService.pay(2L);
orderService.deliver(2L);
orderService.receive(2L);
System.out.println("全部订单状态:" + orderService.getOrders());
return "success";
}
}The execution results show that the Spring State Machine correctly drives the order through each status.
4. Thinking and Summary
Spring State Machine provides a structured way to manage state transitions, but other approaches such as message‑queue driven events, scheduled jobs, or rule‑engine based flows can also be considered.
In summary, the article introduced the State Pattern, explained Spring State Machine concepts, and demonstrated its use in an order‑processing scenario.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
