Spring StateMachine狀態機


一、狀態機

有限狀態機是一種用來進行對象行為建模的工具,其作用主要是描述對象在它的生命周期內所經歷的狀態序列,以及如何響應來自外界的各種事件。在電商場景(訂單、物流、售后)、社交(IM消息投遞)、分布式集群管理(分布式計算平台任務編排)等場景都有大規模的使用。

狀態機的要素:

狀態機可歸納為4個要素,現態、條件、動作、次態。“現態”和“條件”是因,“動作”和“次態”是果。

1 現態:指當前所處的狀態
2 條件:又稱“事件”,當一個條件被滿足,將會觸發一個動作,或者執行一次狀態的遷移
3 動作:條件滿足后執行的動作。動作執行完畢后,可以遷移到新的狀態,也可以仍舊保持原狀態。動作不是必須的,當條件滿足后,也可以不執行任何動作,直接遷移到新的狀態。
4 次態:條件滿足后要遷往的新狀態。“次態”是相對於“現態”而言的,“次態”一旦被激活,就轉換成“現態”。

狀態機動作類型:

進入動作:在進入狀態時進行
退出動作:在退出狀態時進行
輸入動作:依賴於當前狀態和輸入條件進行
轉移動作:在進行特定轉移時進行

二、spring statemachine

spring statemachine是使用 Spring框架下的狀態機概念創建的一種應用程序開發框架。它使得狀態機結構層次化,簡化了配置狀態機的過程。
官方文檔:https://docs.spring.io/autorepo/docs/spring-statemachine/1.0.0.M3/reference/htmlsingle/#sm-stateconte

例子一:簡單訂單流程

訂單狀態流程
使用過程:

1 引入依賴

<!--spring statemachine--> <dependency> <groupId>org.springframework.statemachine</groupId> <artifactId>spring-statemachine-core</artifactId> <version>2.0.1.RELEASE</version> </dependency>

2 創建訂單狀態枚舉類和狀態轉換枚舉類

/** * 訂單狀態 */ public enum OrderStatus { // 待支付,待發貨,待收貨,訂單結束 WAIT_PAYMENT, WAIT_DELIVER, WAIT_RECEIVE, FINISH; }
/** * 訂單狀態改變事件 */ public enum OrderStatusChangeEvent { // 支付,發貨,確認收貨 PAYED, DELIVERY, RECEIVED; }

3 添加配置

/** * 訂單狀態機配置 */ @Configuration @EnableStateMachine(name = "orderStateMachine") public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> { /** * 配置狀態 * @param states * @throws Exception */ @Override public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception { states .withStates() .initial(OrderStatus.WAIT_PAYMENT) .states(EnumSet.allOf(OrderStatus.class)); } /** * 配置狀態轉換事件關系 * @param transitions * @throws Exception */ @Override public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception { transitions .withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED) .and() .withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY) .and() .withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderStatusChangeEvent.RECEIVED); } /** * 持久化配置 * 實際使用中,可以配合redis等,進行持久化操作 * @return */ @Bean public StateMachinePersister<OrderStatus, OrderStatusChangeEvent, Order> persister(){ return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatus, OrderStatusChangeEvent, Order>() { @Override public void write(StateMachineContext<OrderStatus, OrderStatusChangeEvent> context, Order order) throws Exception { //此處並沒有進行持久化操作 } @Override public StateMachineContext<OrderStatus, OrderStatusChangeEvent> read(Order order) throws Exception { //此處直接獲取order中的狀態,其實並沒有進行持久化讀取操作 return new DefaultStateMachineContext<>(order.getStatus(), null, null, null); } }); } }

4 添加訂單狀態監聽器

@Component("orderStateListener") @WithStateMachine(name = "orderStateMachine") public class OrderStateListenerImpl{ @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER") public boolean payTransition(Message<OrderStatusChangeEvent> message) { Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.WAIT_DELIVER); System.out.println("支付 headers=" + message.getHeaders().toString()); return true; } @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE") public boolean deliverTransition(Message<OrderStatusChangeEvent> message) { Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.WAIT_RECEIVE); System.out.println("發貨 headers=" + message.getHeaders().toString()); return true; } @OnTransition(source = "WAIT_RECEIVE", target = "FINISH") public boolean receiveTransition(Message<OrderStatusChangeEvent> message){ Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.FINISH); System.out.println("收貨 headers=" + message.getHeaders().toString()); return true; } }

5 service中使用

@Service("orderService") public class OrderServiceImpl implements OrderService { @Autowired private OrderMapper orderMapper; @Autowired private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine; @Autowired private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, Order> persister; private int id = 1; private Map<Integer, Order> orders = new HashMap<>(); @Override public Order creat() { Order order = new Order(); order.setStatus(OrderStatus.WAIT_PAYMENT); order.setId(id++); orders.put(order.getId(), order); return order; } @Override public Order pay(int id) { Order order = orders.get(id); System.out.println("threadName=" + Thread.currentThread().getName() + " 嘗試支付 id=" + id); Message message = MessageBuilder.withPayload(OrderStatusChangeEvent.PAYED).setHeader("order", order).build(); if (!sendEvent(message, order)) { System.out.println("threadName=" + Thread.currentThread().getName() + " 支付失敗, 狀態異常 id=" + id); } return orders.get(id); } @Override public Order deliver(int id) { Order order = orders.get(id); System.out.println("threadName=" + Thread.currentThread().getName() + " 嘗試發貨 id=" + id); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.DELIVERY).setHeader("order", order).build(), orders.get(id))) { System.out.println("threadName=" + Thread.currentThread().getName() + " 發貨失敗,狀態異常 id=" + id); } return orders.get(id); } @Override public Order receive(int id) { Order order = orders.get(id); System.out.println("threadName=" + Thread.currentThread().getName() + " 嘗試收貨 id=" + id); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.RECEIVED).setHeader("order", order).build(), orders.get(id))) { System.out.println("threadName=" + Thread.currentThread().getName() + " 收貨失敗,狀態異常 id=" + id); } return orders.get(id); } @Override public Map<Integer, Order> getOrders() { return orders; } /** * 發送訂單狀態轉換事件 * * @param message * @param order * @return */ private synchronized boolean sendEvent(Message<OrderStatusChangeEvent> message, Order order) { boolean result = false; try { orderStateMachine.start(); //嘗試恢復狀態機狀態 persister.restore(orderStateMachine, order); //添加延遲用於線程安全測試 Thread.sleep(1000); result = orderStateMachine.sendEvent(message); //持久化狀態機狀態 persister.persist(orderStateMachine, order); } catch (Exception e) { e.printStackTrace(); } finally { orderStateMachine.stop(); } return result; } }

6 測試

@Slf4j @RunWith(SpringRunner.class) @SpringBootTest public class OrderServiceImplTest { @Autowired private OrderService orderService; @Test public void testMultThread(){ orderService.creat(); orderService.creat(); orderService.pay(1); new Thread(()->{ orderService.deliver(1); orderService.receive(1); }).start(); orderService.pay(2); orderService.deliver(2); orderService.receive(2); System.out.println(orderService.getOrders()); } }

例子二:狀態機工廠

有些時候,一個狀態機不夠用,因為我們可能要處理多個訂單。這個時候就要用到了狀態機工廠。

1 配置修改

/** * 訂單狀態機配置 */ @Configuration //@EnableStateMachine(name = "orderStateMachine") @EnableStateMachineFactory(name = "orderStateMachineFactory") public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> { /**訂單狀態機ID*/ public static final String orderStateMachineId = "orderStateMachineId"; /** * 配置狀態 * @param states * @throws Exception */ @Override public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception { states .withStates() .initial(OrderStatus.WAIT_PAYMENT) .states(EnumSet.allOf(OrderStatus.class)); } /** * 配置狀態轉換事件關系 * @param transitions * @throws Exception */ @Override public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception { transitions .withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED) .and() .withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY) .and() .withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderStatusChangeEvent.RECEIVED); } /** * 持久化配置 * 實際使用中,可以配合redis等,進行持久化操作 * @return */ @Bean public StateMachinePersister<OrderStatus, OrderStatusChangeEvent, Order> persister(){ return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatus, OrderStatusChangeEvent, Order>() { @Override public void write(StateMachineContext<OrderStatus, OrderStatusChangeEvent> context, Order order) throws Exception { //此處並沒有進行持久化操作 order.setStatus(context.getState()); } @Override public StateMachineContext<OrderStatus, OrderStatusChangeEvent> read(Order order) throws Exception { //此處直接獲取order中的狀態,其實並沒有進行持久化讀取操作 StateMachineContext<OrderStatus, OrderStatusChangeEvent> result =new DefaultStateMachineContext<>(order.getStatus(), null, null, null, null, orderStateMachineId); return result; } }); } }

2 service中使用

@Service("orderService") public class OrderServiceImpl implements OrderService { @Autowired private OrderMapper orderMapper; // @Autowired // private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine; public static final String stateMachineId = "orderStateMachine"; @Autowired private StateMachineFactory<OrderStatus, OrderStatusChangeEvent> orderStateMachineFactory; @Autowired private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, Order> persister; private int id = 1; private Map<Integer, Order> orders = new HashMap<>(); @Override public Order creat() { Order order = new Order(); order.setStatus(OrderStatus.WAIT_PAYMENT); order.setId(id++); orders.put(order.getId(), order); return order; } @Override public Order pay(int id) { Order order = orders.get(id); System.out.println(" 等待支付 -> 等待發貨 id=" + id + " threadName=" + Thread.currentThread().getName()); Message message = MessageBuilder.withPayload(OrderStatusChangeEvent.PAYED).setHeader("order", order).build(); if (!sendEvent(message, order)) { System.out.println(" 等待支付 -> 等待發貨 失敗, 狀態異常 id=" + id + " threadName=" + Thread.currentThread().getName()); } else { System.out.println(" 等待支付 -> 等待發貨 成功 id=" + id + " threadName=" + Thread.currentThread().getName()); } return orders.get(id); } @Override public Order deliver(int id) { Order order = orders.get(id); System.out.println(" 等待發貨 -> 等待收貨 id=" + id + " threadName=" + Thread.currentThread().getName()); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.DELIVERY).setHeader("order", order).build(), orders.get(id))) { System.out.println(" 等待發貨 -> 等待收貨 失敗,狀態異常 id=" + id + " threadName=" + Thread.currentThread().getName()); } else { System.out.println(" 等待發貨 -> 等待收貨 成功 id=" + id + " threadName=" + Thread.currentThread().getName()); } return orders.get(id); } @Override public Order receive(int id) { Order order = orders.get(id); System.out.println(" 等待收貨 -> 完成 收貨 id=" + id + " threadName=" + Thread.currentThread().getName()); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.RECEIVED).setHeader("order", order).build(), orders.get(id))) { System.out.println(" 等待收貨 -> 完成 失敗,狀態異常 id=" + id + " threadName=" + Thread.currentThread().getName()); } else { System.out.println(" 等待收貨 -> 完成 成功 id=" + id + " threadName=" + Thread.currentThread().getName()); } return orders.get(id); } @Override public Map<Integer, Order> getOrders() { return orders; } /** * 發送訂單狀態轉換事件 * * @param message * @param order * @return */ private boolean sendEvent(Message<OrderStatusChangeEvent> message, Order order) { synchronized (String.valueOf(order.getId()).intern()) { boolean result = false; StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine = orderStateMachineFactory.getStateMachine(stateMachineId); System.out.println("id=" + order.getId() + " 狀態機 orderStateMachine" + orderStateMachine); try { orderStateMachine.start(); //嘗試恢復狀態機狀態 persister.restore(orderStateMachine, order); System.out.println("id=" + order.getId() + " 狀態機 orderStateMachine id=" + orderStateMachine.getId()); //添加延遲用於線程安全測試 Thread.sleep(1000); result = orderStateMachine.sendEvent(message); //持久化狀態機狀態 persister.persist(orderStateMachine, order); } catch (Exception e) { e.printStackTrace(); } finally { orderStateMachine.stop(); } return result; } } }

3 listener中配置id

@Component("orderStateListener") @WithStateMachine(id = OrderStateMachineConfig.orderStateMachineId) public class OrderStateListenerImpl { @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER") public boolean payTransition(Message<OrderStatusChangeEvent> message) { System.out.println("----------------------------"); Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.WAIT_DELIVER); System.out.println("支付 headers=" + message.getHeaders().toString() + " event=" + message.getPayload()); System.out.println("----------------------------"); return true; } @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE") public boolean deliverTransition(Message<OrderStatusChangeEvent> message) { System.out.println("----------------------------"); Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.WAIT_RECEIVE); System.out.println("發貨 headers=" + message.getHeaders().toString() + " event=" + message.getPayload()); System.out.println("----------------------------"); return true; } @OnTransition(source = "WAIT_RECEIVE", target = "FINISH") public boolean receiveTransition(Message<OrderStatusChangeEvent> message) { System.out.println("----------------------------"); Order order = (Order) message.getHeaders().get("order"); order.setStatus(OrderStatus.FINISH); System.out.println("收貨 headers=" + message.getHeaders().toString() + " event=" + message.getPayload()); System.out.println("----------------------------"); return true; } }



轉自 https://www.codetd.com/article/1010726


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM