核心内容摘要
颠覆认知:Luckysheet表格导出效率优化指南——从格式混乱到数据无损迁移的实战手册
这是一个或许对你有用的社群 一对一交流/面试小册/简历优化/求职解惑欢迎加入「芋道快速开发平台」知识星球。
下面是星球提供的部分资料《项目实战视频》从书中学往事中“练”《互联网高频面试题》面朝简历学习春暖花开《架构 x 系统设计》摧枯拉朽掌控面试高频场景题《精进 Java 学习指南》系统学习互联网主流技术栈《必读 Java 源码专栏》知其然知其所以然这是一个或许对你有用的开源项目国产 Star 破 10w 的开源项目前端包括管理后台 微信小程序后端支持单体和微服务架构。
功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能Boot 仓库https://gitee.com/zhijiantianya/ruoyi-vue-proCloud 仓库https://gitee.com/zhijiantianya/yudao-cloud视频教程https://doc.iocoder.cn【国内首批】支持 JDK 21 SpringBoot
3.
2.
JDK 8 Spring Boot
2.
18 双版本来源网络
什么是状态机
1 什么是状态
2 四大概念
3 状态机
状态机图
spring statemachine
1 状态机spring statemachine 概述
2 快速开始
3 测试验证
4 状态机存在的问题
什么是状态机
1 什么是状态先来解释什么是“状态” State 。
现实事物是有不同状态的例如一个自动门就有 open 和 closed 两种状态。
我们通常所说的状态机是有限状态机也就是被描述的事物的状态的数量是有限个例如自动门的状态就是两个 open 和 closed 。
状态机也就是 State Machine 不是指一台实际机器而是指一个数学模型。
说白了一般就是指一张状态转换图。
例如根据自动门的运行规则我们可以抽象出下面这么一个图。
自动门有两个状态open 和 closed closed 状态下如果读取开门信号那么状态就会切换为 open 。
open 状态下如果读取关门信号状态就会切换为 closed 。
状态机的全称是有限状态自动机自动两个字也是包含重要含义的。
给定一个状态机同时给定它的当前状态以及输入那么输出状态时可以明确的运算出来的。
例如对于自动门给定初始状态 closed 给定输入“开门”那么下一个状态时可以运算出来的。
这样状态机的基本定义我们就介绍完毕了。
重复一下状态机是有限状态自动机的简称是现实事物运行规则抽象而成的一个数学模型。
2 四大概念下面来给出状态机的四大概念。
第一个是 State 状态。
一个状态机至少要包含两个状态。
例如上面自动门的例子有 open 和 closed 两个状态。
第二个是 Event 事件。
事件就是执行某个操作的触发条件或者口令。
对于自动门“按下开门按钮”就是一个事件。
第三个是 Action 动作。
事件发生以后要执行动作。
例如事件是“按开门按钮”动作是“开门”。
编程的时候一个 Action一般就对应一个函数。
第四个是 Transition 变换。
也就是从一个状态变化为另一个状态。
例如“开门过程”就是一个变换。
3 状态机有限状态机Finite-state machine,FSM又称有限状态自动机简称状态机是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
FSM是一种算法思想简单而言有限状态机由一组状态、一个初始状态、输入和根据输入及现有状态转换为下一个状态的转换函数组成。
其作用主要是描述对象在它的生命周期内所经历的状态序列以及如何响应来自外界的各种事件。
Java指南https://java-family.cn基于 Spring Boot MyBatis Plus Vue Element 实现的后台管理系统 用户小程序支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能项目地址https://github.com/YunaiV/ruoyi-vue-pro视频教程https://doc.iocoder.cn/video/
状态机图做需求时需要了解以下六种元素起始、终止、现态、次态目标状态、动作、条件我们就可以完成一个状态机图了以订单为例以从待支付状态转换为待发货状态为例①现态是指当前所处的状态。
待支付②条件又称为“事件”当一个条件被满足将会触发一个动作或者执行一次状态的迁移。
支付事件③动作条件满足后执行的动作。
动作执行完毕后可以迁移到新的状态也可以仍旧保持原状态。
动作不是必需的当条件满足后也可以不执行任何动作直接迁移到新状态。
状态转换为待发货④次态条件满足后要迁往的新状态。
“次态”是相对于“现态”而言的“次态”一旦被激活就转变成新的“现态”了。
待发货
注意事项
避免把某个“程序动作”当作是一种“状态”来处理。
那么如何区分“动作”和“状态”“动作”是不稳定的即使没有条件的触发“动作”一旦执行完毕就结束了而“状态”是相对稳定的如果没有外部条件的触发一个状态会一直持续下去。
关注工众号码猿技术专栏回复关键词1111 获取阿里内部Java性能调优手册
状态划分时漏掉一些状态导致跳转逻辑不完整。
所以在设计状态机时我们需要反复的查看设计的状态图或者状态表最终达到一种牢不可破的设计方案。
基于 Spring Cloud Alibaba Gateway Nacos RocketMQ Vue Element 实现的后台管理系统 用户小程序支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能项目地址https://github.com/YunaiV/yudao-cloud视频教程https://doc.iocoder.cn/video/
spring statemachine
1 状态机spring statemachine 概述Spring Statemachine是应用程序开发人员在Spring应用程序中使用状态机概念的框架Spring Statemachine旨在提供以下功能易于使用的扁平单级状态机用于简单的使用案例。
分层状态机结构以简化复杂的状态配置。
状态机区域提供更复杂的状态配置。
使用触发器转换警卫和操作。
键入安全配置适配器。
生成器模式用于在Spring Application上下文之外使用的简单实例化通常用例的食谱基于Zookeeper的分布式状态机状态机事件监听器。
UML Eclipse Papyrus建模。
将计算机配置存储在永久存储中。
Spring IOC集成将bean与状态机关联起来。
状态机功能强大因为行为始终保证一致使调试相对容易。
这是因为操作规则是在机器启动时写成的。
这个想法是你的应用程序可能存在于有限数量的状态中某些预定义的触发器可以将你的应用程序从一个状态转移到另一个状态。
此类触发器可以基于事件或计时器。
在应用程序之外定义高级逻辑然后依靠状态机来管理状态要容易得多。
您可以通过发送事件侦听更改或仅请求当前状态来与状态机进行交互。
官网spring.io/projects/sp…
2 快速开始以订单状态扭转的例子为例表结构设计如下CREATE TABLE tb_order ( id bigint(
unsigned NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_code varchar(
COLLATE utf8mb4_bin DEFAULT NULL COMMENT 订单编码, status smallint(
DEFAULT NULL COMMENT 订单状态, name varchar(
COLLATE utf8mb4_bin DEFAULT NULL COMMENT 订单名称, price decimal(12,
DEFAULT NULL COMMENT 价格, delete_flag tinyint(
NOT NULL DEFAULT 0 COMMENT 删除标记0未删除 1已删除, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 创建时间, update_time timestamp NOT NULL DEFAULT
00:00:00 COMMENT 更新时间, create_user_code varchar(
COLLATE utf8mb4_bin DEFAULT NULL COMMENT 创建人, update_user_code varchar(
COLLATE utf8mb4_bin DEFAULT NULL COMMENT 更新人, version int(
NOT NULL DEFAULT 0 COMMENT 版本号, remark varchar(
COLLATE utf8mb4_bin DEFAULT NULL COMMENT 备注, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT6 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_bin COMMENT订单表; /*Data for the table tb_order */ insert into tb_order(id,order_code,status,name,price,delete_flag,create_time,update_time,create_user_code,update_user_code,version,remark) values (2,A111,1,A,
2
00,0,
16:14:11,
21:29:14,zhangsan,zhangsan,0,NULL), (3,A111,1,订单A,
2
00,0,
21:53:13,
21:29:14,zhangsan,zhangsan,0,NULL), (4,A111,1,订单A,
2
00,0,
21:53:13,
21:29:14,zhangsan,zhangsan,0,NULL), (5,A111,1,订单A,
2
00,0,
09:08:30,
21:29:14,zhangsan,zhangsan,0,NULL);1引入依赖!-- redis持久化状态机 -- dependency groupIdorg.springframework.statemachine/groupId artifactIdspring-statemachine-redis/artifactId version
1.
2.
RELEASE/version /dependency !--状态机-- dependency groupIdorg.springframework.statemachine/groupId artifactIdspring-statemachine-starter/artifactId version
2.
0.
RELEASE/version /dependency2定义状态机状态和事件状态枚举/** * author芋道源码 */ public enum OrderStatus { // 待支付待发货待收货已完成 WAIT_PAYMENT(1, 待支付), WAIT_DELIVER(2, 待发货), WAIT_RECEIVE(3, 待收货), FINISH(4, 已完成); private Integer key; private String desc; OrderStatus(Integer key, String desc) { this.key key; this.desc desc; } public Integer getKey() { return key; } public String getDesc() { return desc; } public static OrderStatus getByKey(Integer key) { for (OrderStatus e : values()) { if (e.getKey().equals(key)) { return e; } } throw new RuntimeException(enum not exists.); } }事件/** * author芋道源码 */ public enum OrderStatusChangeEvent { // 支付发货确认收货 PAYED, DELIVERY, RECEIVED; }3定义状态机规则和配置状态机Configuration EnableStateMachine(name orderStateMachine) public class OrderStateMachineConfig extends StateMachineConfigurerAdapterOrderStatus, OrderStatusChangeEvent { /** * 配置状态 * * param states * throws Exception */ public void configure(StateMachineStateConfigurerOrderStatus, OrderStatusChangeEvent states) throws Exception { states .withStates() .initial(OrderStatus.WAIT_PAYMENT) .states(EnumSet.allOf(OrderStatus.class)); } /** * 配置状态转换事件关系 * * param transitions * throws Exception */ public void configure(StateMachineTransitionConfigurerOrderStatus, 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); } }配置持久化/** * author芋道源码 */ Configuration Slf4j public class PersistE, S { /** * 持久化到内存map中 * * return */ Bean(name stateMachineMemPersister) public static StateMachinePersister getPersister() { return new DefaultStateMachinePersister(new StateMachinePersist() { Override public void write(StateMachineContext context, Object contextObj) throws Exception { log.info(持久化状态机,context:{},contextObj:{}, JSON.toJSONString(context), JSON.toJSONString(contextObj)); map.put(contextObj, context); } Override public StateMachineContext read(Object contextObj) throws Exception { log.info(获取状态机,contextObj:{}, JSON.toJSONString(contextObj)); StateMachineContext stateMachineContext (StateMachineContext) map.get(contextObj); log.info(获取状态机结果,stateMachineContext:{}, JSON.toJSONString(stateMachineContext)); return stateMachineContext; } private Map map new HashMap(); }); } Resource private RedisConnectionFactory redisConnectionFactory; /** * 持久化到redis中在分布式系统中使用 * * return */ Bean(name stateMachineRedisPersister) public RedisStateMachinePersisterE, S getRedisPersister() { RedisStateMachineContextRepositoryE, S repository new RedisStateMachineContextRepository(redisConnectionFactory); RepositoryStateMachinePersist p new RepositoryStateMachinePersist(repository); return new RedisStateMachinePersister(p); } }4业务系统controller/** * author芋道源码 */ RestController RequestMapping(/order) public class OrderController { Resource private OrderService orderService; /** * 根据id查询订单 * * return */ RequestMapping(/getById) public Order getById(RequestParam(id) Long id) { //根据id查询订单 Order order orderService.getById(id); return order; } /** * 创建订单 * * return */ RequestMapping(/create) public String create(RequestBody Order order) { //创建订单 orderService.create(order); return sucess; } /** * 对订单进行支付 * * param id * return */ RequestMapping(/pay) public String pay(RequestParam(id) Long id) { //对订单进行支付 orderService.pay(id); return success; } /** * 对订单进行发货 * * param id * return */ RequestMapping(/deliver) public String deliver(RequestParam(id) Long id) { //对订单进行确认收货 orderService.deliver(id); return success; } /** * 对订单进行确认收货 * * param id * return */ RequestMapping(/receive) public String receive(RequestParam(id) Long id) { //对订单进行确认收货 orderService.receive(id); return success; } }servie/** * author芋道源码 */ Service(orderService) Slf4j public class OrderServiceImpl extends ServiceImplOrderMapper, Order implements OrderService { Resource private StateMachineOrderStatus, OrderStatusChangeEvent orderStateMachine; Resource private StateMachinePersisterOrderStatus, OrderStatusChangeEvent, String stateMachineMemPersister; Resource private OrderMapper orderMapper; /** * 创建订单 * * param order * return */ public Order create(Order order) { order.setStatus(OrderStatus.WAIT_PAYMENT.getKey()); orderMapper.insert(order); return order; } /** * 对订单进行支付 * * param id * return */ public Order pay(Long id) { Order order orderMapper.selectById(id); log.info(线程名称{},尝试支付订单号{} ,Thread.currentThread().getName() , id); if (!sendEvent(OrderStatusChangeEvent.PAYED, order)) { log.error(线程名称{},支付失败, 状态异常订单信息{}, Thread.currentThread().getName(), order); throw new RuntimeException(支付失败, 订单状态异常); } return order; } /** * 对订单进行发货 * * param id * return */ public Order deliver(Long id) { Order order orderMapper.selectById(id); log.info(线程名称{},尝试发货订单号{} ,Thread.currentThread().getName() , id); if (!sendEvent(OrderStatusChangeEvent.DELIVERY, order)) { log.error(线程名称{},发货失败, 状态异常订单信息{}, Thread.currentThread().getName(), order); throw new RuntimeException(发货失败, 订单状态异常); } return order; } /** * 对订单进行确认收货 * * param id * return */ public Order receive(Long id) { Order order orderMapper.selectById(id); log.info(线程名称{},尝试收货订单号{} ,Thread.currentThread().getName() , id); if (!sendEvent(OrderStatusChangeEvent.RECEIVED, order)) { log.error(线程名称{},收货失败, 状态异常订单信息{}, Thread.currentThread().getName(), order); throw new RuntimeException(收货失败, 订单状态异常); } return order; } /** * 发送订单状态转换事件 * synchronized修饰保证这个方法是线程安全的 * * param changeEvent * param order * return */ private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) { boolean result false; try { //启动状态机 orderStateMachine.start(); //尝试恢复状态机状态 stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId())); Message message MessageBuilder.withPayload(changeEvent).setHeader(order, order).build(); result orderStateMachine.sendEvent(message); //持久化状态机状态 stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId())); } catch (Exception e) { log.error(订单操作失败:{}, e); } finally { orderStateMachine.stop(); } return result; } }监听状态的变化/** * author芋道源码 */ Component(orderStateListener) WithStateMachine(name orderStateMachine) Slf4j public class OrderStateListenerImpl { Resource private OrderMapper orderMapper; OnTransition(source WAIT_PAYMENT, target WAIT_DELIVER) public void payTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(支付状态机反馈信息{}, message.getHeaders().toString()); //更新订单 order.setStatus(OrderStatus.WAIT_DELIVER.getKey()); orderMapper.updateById(order); //TODO 其他业务 } OnTransition(source WAIT_DELIVER, target WAIT_RECEIVE) public void deliverTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(发货状态机反馈信息{}, message.getHeaders().toString()); //更新订单 order.setStatus(OrderStatus.WAIT_RECEIVE.getKey()); orderMapper.updateById(order); //TODO 其他业务 } OnTransition(source WAIT_RECEIVE, target FINISH) public void receiveTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(确认收货状态机反馈信息{}, message.getHeaders().toString()); //更新订单 order.setStatus(OrderStatus.FINISH.getKey()); orderMapper.updateById(order); //TODO 其他业务 } }
3 测试验证1验证业务新增一个订单http://localhost:8084/order/create对订单进行支付http://localhost:8084/order/pay?id2对订单进行发货http://localhost:8084/order/deliver?id2对订单进行确认收货http://localhost:8084/order/receive?id2正常流程结束。
如果对一个订单进行支付了再次进行支付则会报错http://localhost:8084/order/pay?id2报错如下2验证持久化内存使用内存持久化类持久化/** * author芋道源码 */ Resource private StateMachinePersisterOrderStatus, OrderStatusChangeEvent, String stateMachineMemPersister; /** * 发送订单状态转换事件 * synchronized修饰保证这个方法是线程安全的 * * param changeEvent * param order * return */ private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) { boolean result false; try { //启动状态机 orderStateMachine.start(); //尝试恢复状态机状态 stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId())); Message message MessageBuilder.withPayload(changeEvent).setHeader(order, order).build(); result orderStateMachine.sendEvent(message); //持久化状态机状态 stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId())); } catch (Exception e) { log.error(订单操作失败:{}, e); } finally { orderStateMachine.stop(); } return result; }redis持久化引入依赖!-- redis持久化状态机 -- dependency groupIdorg.springframework.statemachine/groupId artifactIdspring-statemachine-redis/artifactId version
1.
2.
RELEASE/version /dependency配置yamlspring: redis: database: 0 host: localhost jedis: pool: max-active: 8 max-idle: 8 max-wait: min-idle: 0 password: port: 6379 timeout: 0使用redis持久化类持久化/** * author芋道源码 */ Resource private StateMachinePersisterOrderStatus, OrderStatusChangeEvent, String stateMachineRedisPersister; /** * 发送订单状态转换事件 * synchronized修饰保证这个方法是线程安全的 * * param changeEvent * param order * return */ private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) { boolean result false; try { //启动状态机 orderStateMachine.start(); //尝试恢复状态机状态 stateMachineRedisPersister.restore(orderStateMachine, String.valueOf(order.getId())); Message message MessageBuilder.withPayload(changeEvent).setHeader(order, order).build(); result orderStateMachine.sendEvent(message); //持久化状态机状态 stateMachineRedisPersister.persist(orderStateMachine, String.valueOf(order.getId())); } catch (Exception e) { log.error(订单操作失败:{}, e); } finally { orderStateMachine.stop(); } return result; }
4 状态机存在的问题1stateMachine无法抛出异常异常会被状态机给消化掉问题现象从orderStateMachine.sendEvent(message);获取的结果无法感知到。
无论执行正常还是抛出异常都返回true。
Resource private OrderMapper orderMapper; Resource private StateMachineOrderStatus, OrderStatusChangeEvent orderStateMachine; OnTransition(source WAIT_PAYMENT, target WAIT_DELIVER) Transactional(rollbackFor Exception.class) public void payTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(支付状态机反馈信息{}, message.getHeaders().toString()); try { //更新订单 order.setStatus(OrderStatus.WAIT_DELIVER.getKey()); orderMapper.updateById(order); //TODO 其他业务 //模拟异常 if(Objects.equals(order.getName(),A)){ throw new RuntimeException(执行业务异常); } } catch (Exception e) { //如果出现异常记录异常信息抛出异常信息进行回滚 log.error(payTransition 出现异常{},e); throw e; } }监听事件抛出异常在发送事件中无法感知private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) { boolean result false; try { //启动状态机 orderStateMachine.start(); //尝试恢复状态机状态 stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId())); Message message MessageBuilder.withPayload(changeEvent).setHeader(order, order).build(); //事件执行异常了依然返回true无法感知异常 result orderStateMachine.sendEvent(message); if(result){ //持久化状态机状态如果根据true持久化则会出现问题 stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId())); } } catch (Exception e) { log.error(订单操作失败:{}, e); } finally { orderStateMachine.stop(); } return result; }调试发现发送事件和监听事件是一个线程发送事件的结果是在监听操作执行完之后才返回监听线程解决方案自己保存异常到数据库或者内存中进行判断也可以通过接口org.springframework.statemachine.StateMachine##getExtendedState方法把执行状态放入这个变量中public interface ExtendedState { MapObject, Object getVariables(); T T get(Object var1, ClassT var
; void setExtendedStateChangeListener(ExtendedState.ExtendedStateChangeListener var
; public interface ExtendedStateChangeListener { void changed(Object var1, Object var
; } }org.springframework.statemachine.support.DefaultExtendedState##getVariablesprivate final MapObject, Object variables; public DefaultExtendedState() { this.variables new ObservableMap(new ConcurrentHashMap(), new DefaultExtendedState.LocalMapChangeListener()); } public MapObject, Object getVariables() { return this.variables; }改造监听状态把业务的执行结果进行保存1成功0失败Resource private OrderMapper orderMapper; Resource private StateMachineOrderStatus, OrderStatusChangeEvent orderStateMachine; OnTransition(source WAIT_PAYMENT, target WAIT_DELIVER) Transactional(rollbackFor Exception.class) public void payTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(支付状态机反馈信息{}, message.getHeaders().toString()); try { //更新订单 order.setStatus(OrderStatus.WAIT_DELIVER.getKey()); orderMapper.updateById(order); //TODO 其他业务 //模拟异常 if(Objects.equals(order.getName(),A)){ throw new RuntimeException(执行业务异常); } //成功 则为1 orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransitionorder.getId(),
; } catch (Exception e) { //如果出现异常则进行回滚 log.error(payTransition 出现异常{},e); //将异常信息变量信息中失败则为0 orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransitionorder.getId(),
; throw e; } }发送事件改造如果获取到业务执行异常则返回失败不进行状态机持久化 com.zengqingfa.springboot.state.demo.service.impl.OrderServiceImpl##sendEventResource private StateMachineOrderStatus, OrderStatusChangeEvent orderStateMachine; Resource private StateMachinePersisterOrderStatus, OrderStatusChangeEvent, String stateMachineMemPersister; /** * 发送订单状态转换事件 * synchronized修饰保证这个方法是线程安全的 * * param changeEvent * param order * return */ private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order){ boolean result false; try { //启动状态机 orderStateMachine.start(); //尝试恢复状态机状态 stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId())); Message message MessageBuilder.withPayload(changeEvent).setHeader(order, order).build(); result orderStateMachine.sendEvent(message); if(!result){ return false; } //获取到监听的结果信息 Integer o (Integer) orderStateMachine.getExtendedState().getVariables().get(CommonConstants.payTransition order.getId()); //操作完成之后,删除本次对应的key信息 orderStateMachine.getExtendedState().getVariables().remove(CommonConstants.payTransitionorder.getId()); //如果事务执行成功则持久化状态机 if(Objects.equals(1,Integer.valueOf(o))){ //持久化状态机状态 stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId())); }else { //订单执行业务异常 return false; } } catch (Exception e) { log.error(订单操作失败:{}, e); } finally { orderStateMachine.stop(); } return result; }代码优化发送事件只针对了支付如果是非支付事件呢//获取到监听的结果信息 Integer o (Integer) orderStateMachine.getExtendedState().getVariables().get(CommonConstants.payTransition order.getId());监听设置状态的代码有重复代码需要进行优化可使用aoptry { //TODO 其他业务 //成功 则为1 orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransitionorder.getId(),
; } catch (Exception e) { //如果出现异常则进行回滚 log.error(payTransition 出现异常{},e); //将异常信息变量信息中失败则为0 orderStateMachine.getExtendedState().getVariables().put(CommonConstants.payTransitionorder.getId(),
; throw e; }常量类public interface CommonConstants { String orderHeaderorder; String payTransitionpayTransition; String deliverTransitiondeliverTransition; String receiveTransitionreceiveTransition; }支付发送事件com.zengqingfa.springboot.state.demo.service.impl.OrderServiceImpl##payResource private StateMachineOrderStatus, OrderStatusChangeEvent orderStateMachine; Resource private StateMachinePersisterOrderStatus, OrderStatusChangeEvent, String stateMachineMemPersister; Resource private OrderMapper orderMapper; /** * 对订单进行支付 * * param id * return */ public Order pay(Long id) { Order order orderMapper.selectById(id); log.info(线程名称{},尝试支付订单号{} ,Thread.currentThread().getName() , id); if (!sendEvent(OrderStatusChangeEvent.PAYED, order,CommonConstants.payTransition)) { log.error(线程名称{},支付失败, 状态异常订单信息{}, Thread.currentThread().getName(), order); throw new RuntimeException(支付失败, 订单状态异常); } return order; } /** * 发送订单状态转换事件 * synchronized修饰保证这个方法是线程安全的 * * param changeEvent * param order * return */ private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order,String key){ boolean result false; try { //启动状态机 orderStateMachine.start(); //尝试恢复状态机状态 stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId())); Message message MessageBuilder.withPayload(changeEvent).setHeader(order, order).build(); result orderStateMachine.sendEvent(message); if(!result){ return false; } //获取到监听的结果信息 Integer o (Integer) orderStateMachine.getExtendedState().getVariables().get(key order.getId()); //操作完成之后,删除本次对应的key信息 orderStateMachine.getExtendedState().getVariables().remove(keyorder.getId()); //如果事务执行成功则持久化状态机 if(Objects.equals(1,Integer.valueOf(o))){ //持久化状态机状态 stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId())); }else { //订单执行业务异常 return false; } } catch (Exception e) { log.error(订单操作失败:{}, e); } finally { orderStateMachine.stop(); } return result; }使用aop对监听事件切面把业务执行结果封装到状态机的变量中注解Retention(RetentionPolicy.RUNTIME) public interface LogResult { /** *执行的业务key * * return String */ String key(); }切面Component Aspect Slf4j public class LogResultAspect { //拦截 LogHistory注解 Pointcut(annotation(com.zengqingfa.springboot.state.demo.aop.annotation.LogResult)) private void logResultPointCut() { //logResultPointCut 日志注解切点 } Resource private StateMachineOrderStatus, OrderStatusChangeEvent orderStateMachine; Around(logResultPointCut()) public Object logResultAround(ProceedingJoinPoint pjp) throws Throwable { //获取参数 Object[] args pjp.getArgs(); log.info(参数args:{}, args); Message message (Message) args[0]; Order order (Order) message.getHeaders().get(order); //获取方法 Method method ((MethodSignature) pjp.getSignature()).getMethod(); // 获取LogHistory注解 LogResult logResult method.getAnnotation(LogResult.class); String key logResult.key(); Object returnVal null; try { //执行方法 returnVal pjp.proceed(); //如果业务执行正常则保存信息 //成功 则为1 orderStateMachine.getExtendedState().getVariables().put(key order.getId(),
; } catch (Throwable e) { log.error(e:{}, e.getMessage()); //如果业务执行异常则保存信息 //将异常信息变量信息中失败则为0 orderStateMachine.getExtendedState().getVariables().put(key order.getId(),
; throw e; } return returnVal; } }监听类使用注解Component(orderStateListener) WithStateMachine(name orderStateMachine) Slf4j public class OrderStateListenerImpl { Resource private OrderMapper orderMapper; OnTransition(source WAIT_PAYMENT, target WAIT_DELIVER) Transactional(rollbackFor Exception.class) LogResult(key CommonConstants.payTransition) public void payTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(支付状态机反馈信息{}, message.getHeaders().toString()); //更新订单 order.setStatus(OrderStatus.WAIT_DELIVER.getKey()); orderMapper.updateById(order); //TODO 其他业务 //模拟异常 if (Objects.equals(order.getName(), A)) { throw new RuntimeException(执行业务异常); } } OnTransition(source WAIT_DELIVER, target WAIT_RECEIVE) LogResult(key CommonConstants.deliverTransition) public void deliverTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(发货状态机反馈信息{}, message.getHeaders().toString()); //更新订单 order.setStatus(OrderStatus.WAIT_RECEIVE.getKey()); orderMapper.updateById(order); //TODO 其他业务 } OnTransition(source WAIT_RECEIVE, target FINISH) LogResult(key CommonConstants.receiveTransition) public void receiveTransition(MessageOrderStatusChangeEvent message) { Order order (Order) message.getHeaders().get(order); log.info(确认收货状态机反馈信息{}, message.getHeaders().toString()); //更新订单 order.setStatus(OrderStatus.FINISH.getKey()); orderMapper.updateById(order); //TODO 其他业务 } }欢迎加入我的知识星球全面提升技术能力。
加入方式“长按”或“扫描”下方二维码噢星球的内容包括项目实战、面试招聘、源码解析、学习路线。
文章有帮助的话在看转发吧。
谢谢支持哟 (*^__^*