spring状态机(不太优雅)笔记

文章目录

        • 什么是状态机
      • 事件、动作、业务的区别
      • 普通逻辑和状态机的区别
    • 集成及使用
      • 引入maven依赖
        • 定义状态枚举
        • 定义事件枚举
      • 初始化订单的状态集合以及状态转移事件
        • 状态转移的监听器
        • 测试

听到这个名词一愣,但是很快反应过来了,就是状态和逻辑控制名词化了。

当然,和普通逻辑相比,可不是改个名字而已,有很多不同。

什么是状态机

Java状态机是一种用于描述系统状态转换的模型,通过定义状态、事件、动作和转换规则来控制程序行为。

其核心要素如下:
**状态(States):**系统可能处于的固定状态,如订单状态中的"已支付"、“已发货"等 。 ‌
**事件(Events):**触发状态转换的外部或内部信号,如"支付”、“取消"等操作 。 ‌
**动作(Actions):**状态转换时执行的操作,例如更新状态字段或记录日志 。 ‌
**转换(Transitions):**定义事件触发下状态转移的规则,例如"支付成功"事件将"待支付"状态转为"支付成功”。

这么看是否还得维护个状态表,看起来才比较清楚。

事件、动作、业务的区别

这几个概念容易混淆。
事件:表示触发。
动作:要做的操作:
业务:包含(事件+动作),当然也可能有其他操作。

普通逻辑和状态机的区别

名称普通逻辑状态机
逻辑清晰度需要if else来实现逻辑判断,可读性差状态机通过预定义状态和事件,将状态转换规则显式化,避免冗余的条件判断,可读性强。
扩展性需要在原代码上修改逻辑,易出错,扩展性差。新增状态或事件时,只需扩展状态机配置,无需修改现有代码。
线程安全支持需手动处理同步问题(如使用synchronized或Lock),实现复杂且易出错。状态机框架(如Spring StateMachine)内置线程同步机制,确保并发场景下状态一致性。
业务解耦状态处理常耦合在业务方法内,难以独立测试。 ‌状态机将状态逻辑与业务代码分离,便于测试和复用。
可视化配置普通逻辑需通过代码硬编码状态转换,可读性差。 ‌框架支持通过代码或配置文件定义状态机,直观展示状态迁移路径。

集成及使用

引入maven依赖

<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>2.0.0.RELEASE</version></dependency><!-- uml to code --><dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-uml</artifactId><version>2.0.0.RELEASE</version></dependency>
定义状态枚举

代码:

publicenumStates{UNPAID,// 待支付WAITING_FOR_RECEIVE,// 待收货DONE// 结束}
定义事件枚举

代码:

publicenumEvents{PAY,// 支付RECEIVE// 收货}

初始化订单的状态集合以及状态转移事件

代码:

publicclassStateMachineConfigextendsEnumStateMachineConfigurerAdapter<States,Events>{privateLoggerLOGGER=LoggerFactory.getLogger(getClass());@Overridepublicvoidconfigure(StateMachineStateConfigurer<States,Events>states)throwsException{states.withStates().initial(States.UNPAID).states(EnumSet.allOf(States.class));}@Overridepublicvoidconfigure(StateMachineTransitionConfigurer<States,Events>transitions)throwsException{transitions.withExternal().source(States.UNPAID).target(States.WAITING_FOR_RECEIVE).event(Events.PAY).and().withExternal().source(States.WAITING_FOR_RECEIVE).target(States.DONE).event(Events.RECEIVE);}//守护@BeanpublicGuard<States,Events>guard(){returnnewGuard<States,Events>(){publicbooleanevaluate(StateContext<States,Events>context){returntrue;}};}
状态转移的监听器
@WithStateMachinepublicclassEventListener{privateLoggerLOGGER=LoggerFactory.getLogger(getClass());@OnTransition(target="UNPAID")publicvoidcreate(){//此处可以执行具体业务逻辑处理LOGGER.info("--------------------订单创建,待支付-----------------------");}@OnTransition(source="UNPAID",target="WAITING_FOR_RECEIVE")publicvoidpay(){//此处可以执行具体业务逻辑处理LOGGER.info("--------------------用户完成支付,待收货--------------------");}@OnTransition(source="WAITING_FOR_RECEIVE",target="DONE")publicvoidreceive(){//此处可以执行具体业务逻辑处理LOGGER.info("--------------------用户已收货,订单完成----------------------");}}
测试

测试类代码:

@RunWith(SpringRunner.class)@SpringBootTestpublicclassApplicationTests{@TestpublicvoidcontextLoads(){}@AutowiredprivateStateMachine<States,Events>stateMachine;@Testpublicvoidtest()throwsException{stateMachine.start();stateMachine.sendEvent(Events.PAY);stateMachine.sendEvent(Events.RECEIVE);}}

1.只运行启动

@Testpublicvoidtest()throwsException{stateMachine.start();//springboot启动时开启 待支付//stateMachine.sendEvent(Events.PAY); //支付操作 待收货//stateMachine.sendEvent(Events.RECEIVE); //收货操作 结束}

2.运行启动与支付操作

@Testpublicvoidtest()throwsException{stateMachine.start();//springboot启动时开启 待支付//stateMachine.sendEvent(Events.PAY); //支付操作 待收货//stateMachine.sendEvent(Events.RECEIVE); //收货操作 结束}

3.全部执行

@Testpublicvoidtest()throwsException{stateMachine.start();//springboot启动时开启 待支付stateMachine.sendEvent(Events.PAY);//支付操作 待收货stateMachine.sendEvent(Events.RECEIVE);//收货操作 结束}