3. Implementing Order State Transition with Spring State Machine

0 24
When talking about Spring state machine, people often think about what the diffe...

When talking about Spring state machine, people often think about what the difference is between this state machine and the state pattern in design patterns. That's right, Spring state machine is one of the implementations of the state pattern. Before introducing Spring state machine, let's take a look at the state pattern in design patterns.

1. State Pattern

The definition of the state pattern is as follows:

State Pattern(State Pattern)It is a behavioral design pattern that allows an object to change its behavior when its internal state changes. In the state pattern, an object's behavior depends on its current state, and this state can be changed at any time. The state pattern encapsulates the state of an object in different state classes, making the code clearer and easier to maintain. When the state of an object changes, the state pattern will automatically update the behavior of the object without the need for manual judgment and processing in the code.

In most business systems, there are some objects with states, and these states can be converted between each other, and they will show different behaviors or functions under different states, such as in traffic light control systems, there will be red lights, green lights, and yellow lights, and in order systems, orders will have states such as ordered, pending payment, pending shipment, and pending receipt, etc. These states will be converted to each other through different behaviors. At this point, when designing the system, the state pattern can be used.

Below isState PatternofClass Diagram:


It can be seen that the state pattern mainly includes three types of roles:

1. Context (Context) RoleIt encapsulates the instances of the state, responsible for maintaining state instances, and delegates requests to the current state object.

2. Abstract State (State) RoleIt defines interfaces representing different states and encapsulates the behavior under each state. All specific states implement this interface.

3. Concrete states(Concrete State) Role: Specifically implements the interface of the abstract state role and encapsulates the behavior under the state.

Below is the implementation using the state patternTraffic lightsA simple example of state change:

Abstract state class:

/**
 * @description: Abstract state class
 */public abstract class MyState { abstract void handler(); }

Concrete state class A

/**
 * @description: Concrete state A
 */public class RedLightState extends MyState { @Override void handler() { System.out.println("Red light stop"); } }

Concrete state class B

/**
 * @description: Concrete state B
 */public class GreenLightState extends MyState { @Override void handler() { System.out.println("Green light go"); } }

Environment class: Maintains the current state object and provides methods for state switching.

/**
 * @description: Environment class
 */public class MyContext { private MyState state; public void setState(MyState state) { this.state = state; } public void handler() { state.handler(); } }

Test class

/**
 * @description: Test state pattern
 */public class TestStateModel { public static void main(String[] args) { MyContext myContext = new MyContext(); RedLightState redLightState = new RedLightState(); GreenLightState greenLightState = new GreenLightState(); myContext.setState(redLightState); myContext.handler(); // Red light stop myContext.setState(greenLightState); myContext.handler(); // Green light go }}

Below is the corresponding execution result


It can be found that to some extent, the state class in the state pattern also eliminates the if-else logic check. Seeing this, some people may have doubts: what is the difference between the state pattern and the strategy pattern?

The state pattern is more concerned with the behavior of objects in different states and the transition between states, while the strategy pattern is more concerned with the selection of different strategies by objects.

We introduced the state pattern in the design pattern above. Next, let's take a look at the Spring state machine.

2. Spring state machine

State machine, or State Machine, does not refer to an actual machine, but rather a mathematical model. In short, it refers to a state transition diagram.The state machine is an application of the state pattern, which is equivalent to an upgraded version of the context role. It is widely used in various systems such as workflows and games, such as various workflow engines. It is almost a subset and implementation of the state machine, encapsulating the rules of state changes. Spring also provides a good solution. The component name in Spring is called StateMachine. The state machine helps developers simplify the development process of state control, making the state machine structure more hierarchical.

Through definition, it is easy to analyze the following elements that the state machine should have:

1.Current state:That is, the starting state of the state transition.

2.Triggering event:A series of actions that cause the transition between states.

3.Response function:The rules between the triggering event and the next state.

4.Target state: the target state of the state transition.

For componentized state machines, the two most commonly used ones at present are: one is the Spring state machine, and the other is the COLA state machine. The comparison of these two state machines is shown in the following table:

Spring state machineCOLA state machine
API callAPI calls using Reactive's Mono, Flux methodsSynchronous API calls, and asynchronous calls can also be made through message queues, scheduled tasks, multithreading, and other methods if needed
Code volumecore package with 284 interfaces and classes36 interfaces and classes
EcosystemVery richRelatively barren
Customization difficultyDifficultSimple

It can be seen that the Spring state machine provides a rich set of features, of course, it is not as good as COLA state machine in terms of customization. If there is a high demand for customization, it is recommended to use COLA state machine.

This article takes the Spring state machine as an example to show how to use the state machine in business systems.

To facilitate everyone's understanding of the implementation principle, usage method, and provided functions of the Spring state machine, the official documentation and source code are listed below. Interested students can read them.

Official Documentation: https://docs.spring.io/spring-statemachine/docs/4.0.0/reference/index.html#statemachine-config-states

Source Code: https://github.com/spring-projects/spring-statemachine

3. Implementing Order State Transition with Spring State Machine

For the state pattern, Spring has encapsulated a component called State Machine (StateMachine). The Spring state machine can help developers simplify the development process of state control, making the state machine structure more hierarchical. Below, we use the Spring state machine to simulate the process of order state transition.

3.1 Environment Preparation

Firstly, if you want to use the Spring state machine, you need to introduce the corresponding jar package, here my Spring Boot version is: 2.2.1.RELEASE

<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>${springboot.version}</version></dependency>

Below is the simplified definition of the order, as well as the enumerations of order status and order transition behavior

/**
 * @description: Simulated order class
 */@Data public class Order{private Long orderId;private OrderStatusEnum orderStatus;}/**
 * @description: Order status
 */public enum OrderStatusEnum{// Waiting for payment WAIT_PAYMENT,// Waiting for delivery WAIT_DELIVER,// Waiting for receipt WAIT_RECEIVE,// Completed FINISH;}/**
 * @description: Order status transition behavior
 */public enum OrderStatusChangeEventEnum{// Payment PAYED,// Delivery DELIVERY,// Receipt RECEIVED;}

3.2 Constructing the Order State Machine

After introducing the jar package, a state machine for the order state transition needs to be built

The configuration class of the order state machine is as follows:

/**
 * @description: Order state machine
 */@Configuration@EnableStateMachinepublicclassOrderStatusMachineConfigextendsStateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEventEnum>{/**}
     * Configure states
     */@Overridepublicvoidconfigure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum>states)throwsException{states.withStates().initial(OrderStatusEnum.WAIT_PAYMENT).end(OrderStatusEnum.FINISH).states(EnumSet.allOf(OrderStatusEnum.class));}/**
     * Configure state transition event relationships
     */@Overridepublicvoidconfigure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum>transitions)throwsException{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 Write State Machine Listener

Listen to state change events and complete state transitions.

/**
 * @description: State 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("Payment, state machine feedback information: "+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("Delivery, state machine feedback information: "+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("Receiving, state machine feedback information: "+message.getHeaders().toString()); return true;}}

3.4 Write Order Service Class

Simulate some business operations on orders

/**
 * @description: Order service
 */@Service public class OrderServiceImpl implements OrderService {@Resource privateStateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine; private long id = 1L; privateMap<Long, Order> orders = Maps.newConcurrentMap(); @Override public Order create() { Order order = new Order(); order.setOrderStatus(OrderStatusEnum.WAIT_PAYMENT); order.setOrderId(id++); orders.put(order.getOrderId(), order); System.out.println("Order created successfully:" + order.toString()); return order; } @Override public Order pay(long id) { Order order = orders.get(id); System.out.println("Attempt to pay, order number: " + id); Message message = MessageBuilder.withPayload(OrderStatusChangeEventEnum.PAYED).setHeader("order", order).build(); if (!sendEvent(message)) { System.out.println("Payment failed, status exception, order number: " + id); } return orders.get(id); } @Override public Order deliver(long id) { Order order = orders.get(id); System.out.println("Attempt to deliver, order number: " + id); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.DELIVERY).setHeader("order", order).build())){System.out.println(" 发货失败,状态异常,订单号:"+id);}returnorders.get(id);}@OverridepublicOrderreceive(longid){Orderorder =orders.get(id);System.out.println(" 尝试收货,订单号:"+id);if(!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.RECEIVED).setHeader("order",order).build())){System.out.println(" 收货失败,状态异常,订单号:"+id);}returnorders.get(id);}@OverridepublicMapgetOrders(){returnorders;}/**
     * Send status transition event
     * @param message
     * @return
     */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; }}

3.5 Test Entry

Here, a controller is written to simulate a client-side user request. For the sake of demonstration, a test method is used to complete all operations.

@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("All order statuses: " + orderService.getOrders()); return "success"; }}

Below is the corresponding execution result


As can be seen, the Spring state machine has well-controlled the transition of orders between various states.

4. Thoughts and Summary

Thoughts: In view of the characteristics of the state machine, are there other ways to implement a state machine? Below are some common approaches, and other methods are welcome to be left in the comments section.

1. Message Queue Method

The order state transition can be published through a message queue, and the consumer can transition the order state based on business conditions, and different events can be sent to different Topics.

2. Scheduled Task Driven

Start the job at regular intervals, retrieve the corresponding order records from the database based on a specific state, and then judge whether the order has conditions to reach the next state.

3. Rule Engine Method

The business team can write a series of states and their corresponding transition rules in the rule engine. The rule engine parses the input data according to the loaded rules and executes the corresponding actions based on the parsing results to complete the state transition.

Summary:

This article mainly introduces the State Pattern in design patterns, and on this basis, it introduces the related concepts of Spring State Machine. According to common order flow scenarios, it describes the usage of Spring State Machine. Any inaccuracies in the text are welcome to be criticized and corrected in the comments section.

5. Reference Content

https://docs.spring.io/spring-statemachine/docs/4.0.0/reference/index.html#statemachine-config-states

https://cloud.tencent.com/developer/article/2198477?areaId=106001

https://cloud.tencent.com/developer/article/2360708?areaId=106001

https://juejin.cn/post/7087064901553750030

https://my.oschina.net/u/4090830/blog/10092135

https://juejin.cn/post/7267506576448929811

Author: JD Technology, Sun Yangwei

Source: JD Cloud Developer Community. Please indicate the source when转载.

你可能想看:

It is possible to perform credible verification on the system boot program, system program, important configuration parameters, and application programs of computing devices based on a credible root,

d) Adopt identification technologies such as passwords, password technologies, biometric technologies, and combinations of two or more to identify users, and at least one identification technology sho

About the related technologies and implementations associated with tracing the source of posts by PDD employees

In today's rapidly developing digital economy, data has become an important engine driving social progress and enterprise development. From being initially regarded as part of intangible assets to now

(3) Is the national secret OTP simply replacing the SHA series hash algorithms with the SM3 algorithm, and becoming the national secret version of HOTP and TOTP according to the adopted dynamic factor

Distributed Storage Technology (Part 2): Analysis of the architecture, principles, characteristics, and advantages and disadvantages of wide-column storage and full-text search engines

Announcement regarding the addition of 7 units as technical support units for the Ministry of Industry and Information Technology's mobile Internet APP product security vulnerability database

A Brief Discussion on the Establishment of Special Security Management Organizations for Operators of Key Information Infrastructure

4.5 Main person in charge reviews the simulation results, sorts out the separated simulation issues, and allows the red and blue teams to improve as soon as possible. The main issues are as follows

In-depth Analysis: Mining Trojan Analysis and Emergency Response Disposal Under a Complete Attack Chain

最后修改时间:
admin
上一篇 2025年03月25日 21:27
下一篇 2025年03月25日 21:50

评论已关闭