赞
踩
状态机是状态模式的一种应用,相当于上下文角色的一个升级版。在工作流或游戏等各种系统中有大量使用,如各种工作流引擎,它几乎是状态机的子集和实现,封装状态的变化规则。状态机可以帮助开发者简化状态控制的开发过程,让状态机结构更加层次化。
把状态机的要素分为4个要素,即:现态、条件、动作、次态。
“现态”和“条件”是因,“动作”和“次态”是果。
(1)现态:是指当前所处状态;
(2)条件:又称为“事件”。当条件被满足时,将会触发一个动作,或者执行一次状态的迁移。
(3)动作:条件满足后执行的动作。动作不是必须的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
(4)次态:条件满足后要迁移往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
在电商平台中,一个订单会有多种状态,临时单、已下单、待支付、已支付、待发货、待收货、已完成等等。每一种状态都和变化前的状态以及执行的操作有关。
比如,用户将商品加入购物车后,后台会生成一个所谓的“临时单”。因为用户还没有点击下单,所以这个订单实际上还没有生成。只有当用户下单后,这个“临时单”才会转化为一个“待支付的订单”。
以上过程中只有将一个处于“临时单”状态的订单执行下单操作,才能得到一个状态为“待支付”的订单。 即一个前置状态+一个恰当的操作,才能流转订单的状态。在这个过程中如果使用硬编码,我们就需要一系列的 if-else 语句来检查订单的当前状态、可执行操作以及这两个组合得到的下一个应该被流转的状态值。如果订单的状态流转很复杂,代码逻辑就会很复杂,可读性低,后期维护困难。
处理以上问题,我们可以使用状态设计模式来处理。对应到实践,就是状态机。
Spring 提供了一个很好的解决方案,Spring Statemachine(状态机)是应用程序开发人员在 Spring 应用程序中使用状态机概念的框架。
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
package com.sky.statemachinedemo.entity;
import lombok.Data;
/**
* 订单实体类
*/
@Data
public class Order {
private Integer id;
private Integer status;
}
package com.sky.statemachinedemo.constants; /** * 订单状态枚举 */ public enum OrderStatusEnum { /** * 待付款 */ WAIT_PAYMENT(0), /** * 待发货 */ WAIT_DELIVER(1), /** * 待收货 */ WAIT_RECEIVE(2), /** * 已完成 */ FINISH(3), /** * 取消 */ CANCEL(4), ; /** * 订单状态 */ public final int value; OrderStatusEnum(int value) { this.value = value; } public static Object getByValue(Integer status) { for(OrderStatusEnum OrderStatusEnum:OrderStatusEnum.values()){ if(OrderStatusEnum.value==status){ return OrderStatusEnum; } } return null; } }
package com.sky.statemachinedemo.constants;
/**
* 状态转换枚举类(事件)
*/
public enum OrderStatusChangeEvent {
// 支付,发货,确认收货
PAYED, DELIVERY, RECEIVED,CANCEL;
}
package com.sky.statemachinedemo.config; import com.sky.statemachinedemo.constants.OrderStatusChangeEvent; import com.sky.statemachinedemo.constants.OrderStatusEnum; import com.sky.statemachinedemo.entity.Order; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.statemachine.StateMachineContext; import org.springframework.statemachine.StateMachinePersist; import org.springframework.statemachine.config.EnableStateMachine; import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; import org.springframework.statemachine.persist.DefaultStateMachinePersister; import org.springframework.statemachine.support.DefaultStateMachineContext; import java.util.EnumSet; /** * 订单状态机配置 */ @Slf4j @Configuration @EnableStateMachine(name = "OrderStateMachine") public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEvent> { /** * 配置状态 * * @param states * @throws Exception */ public void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusChangeEvent> states) throws Exception { states .withStates() .initial(OrderStatusEnum.WAIT_PAYMENT) .states(EnumSet.allOf(OrderStatusEnum.class)); } /** * 配置状态转换事件关系 * * @param transitions * @throws Exception */ public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusChangeEvent> transitions) throws Exception { transitions .withExternal().source(OrderStatusEnum.WAIT_PAYMENT).target(OrderStatusEnum.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED) .and() .withExternal().source(OrderStatusEnum.WAIT_PAYMENT).target(OrderStatusEnum.CANCEL).event(OrderStatusChangeEvent.CANCEL) .and() .withExternal().source(OrderStatusEnum.WAIT_DELIVER).target(OrderStatusEnum.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY) .and() .withExternal().source(OrderStatusEnum.WAIT_RECEIVE).target(OrderStatusEnum.FINISH).event(OrderStatusChangeEvent.RECEIVED); } /** * 持久化配置 * 实际使用中,可以配合redis等,进行持久化操作 * * @return */ @Bean public DefaultStateMachinePersister persister() { return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatusEnum, OrderStatusChangeEvent, Order>() { @Override public void write(StateMachineContext<OrderStatusEnum, OrderStatusChangeEvent> context, Order Order) throws Exception { //此处并没有进行持久化操作 //此处可调用更新状态流转接口(如:更新时间)状态不需要在此进行调用 } @Override public StateMachineContext<OrderStatusEnum, OrderStatusChangeEvent> read(Order Order) throws Exception { //此处直接获取Order中的状态,其实并没有进行持久化读取操作 //实际生产中我们会查询出订单信息,根据订单状态获取状态机状态 return new DefaultStateMachineContext(OrderStatusEnum.getByValue(Order.getStatus()), null, null, null); } }); } }
package com.sky.statemachinedemo.listener; import com.sky.statemachinedemo.constants.OrderStatusChangeEvent; import com.sky.statemachinedemo.constants.OrderStatusEnum; import com.sky.statemachinedemo.entity.Order; import org.springframework.messaging.Message; import org.springframework.statemachine.annotation.OnTransition; import org.springframework.statemachine.annotation.WithStateMachine; import org.springframework.stereotype.Component; /** * 订单状态监听器 */ @Component("OrderStateListener") @WithStateMachine(name = "OrderStateMachine") public class OrderStateListener { @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER") public boolean payTransition(Message<OrderStatusChangeEvent> message) { Order Order = (Order) message.getHeaders().get("order"); Order.setStatus(OrderStatusEnum.WAIT_DELIVER.value); System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString()); return true; } @OnTransition(source = "WAIT_PAYMENT", target = "CANCEL") public boolean cancelTransition(Message<OrderStatusChangeEvent> message) { Order Order = (Order) message.getHeaders().get("order"); Order.setStatus(OrderStatusEnum.CANCEL.value); System.out.println("支付,状态机反馈信息:" + 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(OrderStatusEnum.WAIT_RECEIVE.value); System.out.println("发货,状态机反馈信息:" + 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(OrderStatusEnum.FINISH.value); System.out.println("收货,状态机反馈信息:" + message.getHeaders().toString()); return true; } }
此处也可以单独添加监听,比如:
package com.sky.statemachinedemo.listener; import com.sky.statemachinedemo.constants.OrderStatusChangeEvent; import com.sky.statemachinedemo.constants.OrderStatusEnum; import com.sky.statemachinedemo.entity.Order; import lombok.extern.slf4j.Slf4j; import org.springframework.statemachine.StateContext; import org.springframework.statemachine.action.Action; import org.springframework.stereotype.Component; @Slf4j @Component public class FinishListener implements Action<OrderStatusEnum, OrderStatusChangeEvent> { @Override public void execute(StateContext<OrderStatusEnum, OrderStatusChangeEvent> stateContext) { Order order = (Order) stateContext.getMessage().getHeaders().get("order"); order .setStatus(OrderStatusEnum.FINISH.value); System.out.println("收货,状态机反馈信息:" + stateContext.getMessage().getHeaders().toString()); //可以设置返回值 context.getStateMachine().getExtendedState().getVariables().put("order", order ); } }
config修改:
/** * 配置状态转换事件关系 * * @param transitions * @throws Exception */ public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusChangeEvent> transitions) throws Exception { transitions .withExternal().source(OrderStatusEnum.WAIT_PAYMENT).target(OrderStatusEnum.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED) .and() .withExternal().source(OrderStatusEnum.WAIT_PAYMENT).target(OrderStatusEnum.CANCEL).event(OrderStatusChangeEvent.CANCEL) .and() .withExternal().source(OrderStatusEnum.WAIT_DELIVER).target(OrderStatusEnum.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY) .and() .withExternal().source(OrderStatusEnum.WAIT_RECEIVE).target(OrderStatusEnum.FINISH).event(OrderStatusChangeEvent.RECEIVED).action(finishListener,transitionExceptionListener); }
package com.sky.statemachinedemo.service; import com.sky.statemachinedemo.entity.Order; import java.util.Map; public interface OrderService { //创建订单 Order create(); //发起支付 Order pay(Integer id); //发起支付 Order cancel(Integer id); //订单发货 Order deliver(Integer id); //订单收货 Order receive(Integer id); //获取所有订单信息 //模拟数据存储的订单信息,生产中用数据库存储 Map<Integer, Order> getOrders(); }
package com.sky.statemachinedemo.service; import com.sky.statemachinedemo.constants.OrderStatusChangeEvent; import com.sky.statemachinedemo.constants.OrderStatusEnum; import com.sky.statemachinedemo.entity.Order; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.persist.StateMachinePersister; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Service public class OrderServiceImpl implements OrderService{ @Autowired private StateMachine<OrderStatusEnum, OrderStatusChangeEvent> orderStateMachine; @Autowired private StateMachinePersister<OrderStatusEnum, OrderStatusChangeEvent, Order> persister; private int id = 1; private Map<Integer, Order> orders = new HashMap<>(); @Override public Order create() { Order order = new Order(); order.setStatus(OrderStatusEnum.WAIT_PAYMENT.value); order.setId(id++); orders.put(order.getId(), order); return order; } @Override public Order pay(Integer id) { Order order = orders.get(id); System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试支付,订单号:" + id); Message message = MessageBuilder.withPayload(OrderStatusChangeEvent.PAYED).setHeader("order", order).build(); if (!sendEvent(message, order)) { System.out.println("线程名称:" + Thread.currentThread().getName() + " 支付失败, 状态异常,订单号:" + id); } return orders.get(id); } @Override public Order cancel(Integer id) { Order order = orders.get(id); System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试取消,订单号:" + id); Message message = MessageBuilder.withPayload(OrderStatusChangeEvent.CANCEL).setHeader("order", order).build(); if (!sendEvent(message, order)) { System.out.println("线程名称:" + Thread.currentThread().getName() + " 取消失败, 状态异常,订单号:" + id); } return orders.get(id); } @Override public Order deliver(Integer id) { Order order = orders.get(id); System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试发货,订单号:" + id); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.DELIVERY).setHeader("order", order).build(), orders.get(id))) { System.out.println("线程名称:" + Thread.currentThread().getName() + " 发货失败,状态异常,订单号:" + id); } return orders.get(id); } @Override public Order receive(Integer id) { Order order = orders.get(id); System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" + id); if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEvent.RECEIVED).setHeader("order", order).build(), orders.get(id))) { System.out.println("线程名称:" + Thread.currentThread().getName() + " 收货失败,状态异常,订单号:" + id); } //可以获取返回值 orderStateMachine.getExtendedState().get("order", Order.class); return orders.get(id); } @Override public Map<Integer, Order> getOrders() { return orders; } /** * 发送订单状态转换事件 这里不要使用synchronized锁方法,效率比较低,分布式系统优先采用分布式锁,下单锁userId,订单状态流转锁orderId根据业务考虑使用什么。 * * @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; } }
package com.sky.statemachinedemo.service; import com.sky.statemachinedemo.StateMachineDemoApplication; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest(classes = StateMachineDemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) public class OrderServiceTest extends TestCase { @Autowired OrderService orderService; @Test public void stateTest(){ orderService.create(); orderService.pay(1); orderService.deliver(1); orderService.receive(1); orderService.cancel(1); } }
package com.sky.statemachinedemo.controller; import com.sky.statemachinedemo.entity.Order; import com.sky.statemachinedemo.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/order") public class OrderController { @Autowired OrderService orderService; @RequestMapping("/create") public Order create(){ return orderService.create(); } @RequestMapping("/cancel") public Order cancel(Integer orderId){ return orderService.cancel(orderId); } @RequestMapping("/pay") public Order pay(Integer orderId){ return orderService.pay(orderId); } @RequestMapping("/deliver") public Order deliver(Integer orderId){ return orderService.deliver(orderId); } @RequestMapping("/receive") public Order receive(Integer orderId){ return orderService.receive(orderId); } }
https://blog.csdn.net/bxp1321/article/details/130587651
https://blog.csdn.net/qq_45443879/article/details/123992480
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。