概要:Spring Statemachine
状态机之所以强大,是因为始终保证行为是一致的,这使得调试相对容易。这是因为在机器启动时,操作规则是不可更改的。其思想是,应用程序可能存在有限数量的状态,某些预定义的触发器可以将应用程序从一种状态转移到另一种状态。这样的触发器可以基于事件或计时器。
在应用程序之外定义高级逻辑,然后依靠状态机来管理状态要容易得多。您可以通过发送事件、侦听更改或请求当前状态来与状态机交互。
官网地址:https://projects.spring.io/spring-statemachine/
-
依赖
<dependency> <groupId>org.springframework.statemachine</groupId> <artifactId>spring-statemachine-core</artifactId> <version>2.1.3.RELEASE</version> </dependency>
-
定义事件和状态枚举类
package com.example.statemachine.constant; /** * @author liuteng */ public enum OrderEvent { /** 准备发货 */ READY_SEND("ready_send","准备发货"), /** 确认收货 */ CONFIRM_ACC("confirm_acc", "确认收货"), /**退款成功 */ REFUND_SUC("refund_suc", "退款成功"); private String eventCode; private String eventDesc; OrderEvent(String eventCode, String eventDesc) { this.eventCode = eventCode; this.eventDesc = eventDesc; } public String getEventCode() { return eventCode; } public String getEventDesc() { return eventDesc; } }
package com.example.statemachine.constant; /** * @author liuteng */ public enum OrderStatus { /** 已支付 */ PAID(20), /** 已发货 */ SEND(40), /** 确认收货 */ RECEIVE(60), /** 已退款 */ RETURN(80); private Integer code; OrderStatus(Integer code) { this.code = code; } public Integer getCode() { return code; } public static OrderStatus getOrderStatus(Integer code) { for (OrderStatus status : OrderStatus.values()) { if (status.getCode().equals(code)) { return status; } } return null; } }
-
配置文件
package com.example.statemachine.config; import com.example.statemachine.bean.Order; import com.example.statemachine.constant.OrderEvent; import com.example.statemachine.constant.OrderStatus; 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.persist.StateMachinePersister; import org.springframework.statemachine.support.DefaultStateMachineContext; import java.util.EnumSet; /** * @author liuteng */ @Configuration @EnableStateMachine(name = "orderStateMachine") public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderEvent> { /** * 定义状态机初始状态和所有的状态定义 */ @Override public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvent> states) throws Exception { states.withStates().initial(OrderStatus.PAID).states(EnumSet.allOf(OrderStatus.class)); } /** * 定义状态机状态事件 */ @Override public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) throws Exception { transitions.withExternal() .source(OrderStatus.PAID).target(OrderStatus.SEND) .event(OrderEvent.READY_SEND) .and() .withExternal() .source(OrderStatus.SEND).target(OrderStatus.RECEIVE) .event(OrderEvent.CONFIRM_ACC) .and() .withExternal() .source(OrderStatus.RECEIVE).target(OrderStatus.RETURN) .event(OrderEvent.REFUND_SUC); } /** * 状态机状态与订单状态的同步 */ @Bean public StateMachinePersister<OrderStatus, OrderEvent, Order> persister() { return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatus, OrderEvent, Order>() { @Override public void write(StateMachineContext<OrderStatus, OrderEvent> context, Order order) { order.setStatus(context.getState().getCode()); } @Override public StateMachineContext<OrderStatus, OrderEvent> read(Order order) { return new DefaultStateMachineContext<>(OrderStatus.getOrderStatus(order.getStatus()), null, null, null); } }); } }
-
service
package com.example.statemachine.service.impl; import com.example.statemachine.bean.Order; import com.example.statemachine.constant.OrderEvent; import com.example.statemachine.constant.OrderStatus; import com.example.statemachine.service.OrderStatusManageService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.persist.StateMachinePersister; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * @author liuteng */ @Service public class OrderStatusManageServiceImpl implements OrderStatusManageService { @Resource private StateMachine<OrderStatus, OrderEvent> orderStateMachine; @Autowired private StateMachinePersister<OrderStatus, OrderEvent, Order> persister; @Override public boolean modifyOrderStatus(OrderEvent event, Order order) { boolean result = false; try { orderStateMachine.start(); persister.restore(orderStateMachine, order); result = orderStateMachine.sendEvent(event); persister.persist(orderStateMachine, order); } catch (Exception e) { e.printStackTrace(); } return result; } }
-
测试
package com.example.statemachine; import com.example.statemachine.bean.Order; import com.example.statemachine.constant.OrderEvent; import com.example.statemachine.constant.OrderStatus; import com.example.statemachine.service.OrderStatusManageService; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; /** * @author liuteng */ @SpringBootApplication public class StateMachineApplication { private static final String FORMAT = "事件: %s 单号: %s, 状态: %s"; public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(StateMachineApplication.class, args); OrderStatusManageService orderStatusManageService = context.getBean(OrderStatusManageService.class); Order order = new Order(); order.setOid("1001200006"); order.setStatus(OrderStatus.PAID.getCode()); boolean result = orderStatusManageService.modifyOrderStatus(OrderEvent.READY_SEND, order); if (result) { System.out.println(String.format(FORMAT, OrderEvent.READY_SEND.getEventCode(), order.getOid(), order.getStatus())); } } }
-
结果
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.0.RELEASE) 2020-06-04 17:25:56.773 INFO 14020 --- [ main] c.e.s.StateMachineApplication : Starting StateMachineApplication on P17751033130 with PID 14020 (D:\myProject\state_machine\target\classes started by 17751033130 in D:\myProject\state_machine) 2020-06-04 17:25:56.775 INFO 14020 --- [ main] c.e.s.StateMachineApplication : No active profile set, falling back to default profiles: default 2020-06-04 17:25:57.156 INFO 14020 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration' of type [org.springframework.statemachine.config.configuration.StateMachineAnnotationPostProcessorConfiguration$$EnhancerBySpringCGLIB$$b6c390ca] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2020-06-04 17:25:57.305 INFO 14020 --- [ main] c.e.s.StateMachineApplication : Started StateMachineApplication in 0.929 seconds (JVM running for 1.661) 2020-06-04 17:25:57.313 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608 2020-06-04 17:25:57.313 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started RETURN PAID RECEIVE SEND / PAID / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null 2020-06-04 17:25:57.313 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608 2020-06-04 17:25:57.314 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : stopped RETURN PAID RECEIVE SEND / / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null 2020-06-04 17:25:57.314 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started ObjectState [getIds()=[PAID], getClass()=class org.springframework.statemachine.state.ObjectState, hashCode()=544386226, toString()=AbstractState [id=PAID, pseudoState=org.springframework.statemachine.state.DefaultPseudoState@50ecde95, deferred=[], entryActions=[], exitActions=[], stateActions=[], regions=[], submachine=null]] 2020-06-04 17:25:57.315 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608 2020-06-04 17:25:57.315 INFO 14020 --- [ main] o.s.s.support.LifecycleObjectSupport : started RETURN PAID RECEIVE SEND / PAID / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null 事件: ready_send 单号: 1001200006, 状态: 40 2020-06-04 17:25:57.327 INFO 14020 --- [extShutdownHook] o.s.s.support.LifecycleObjectSupport : stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@6b00f608 2020-06-04 17:25:57.327 INFO 14020 --- [extShutdownHook] o.s.s.support.LifecycleObjectSupport : stopped RETURN PAID RECEIVE SEND / / uuid=9bfb49ee-bbb7-4f7b-9850-653ef746b392 / id=null 2020-06-04 17:25:57.327 INFO 14020 --- [extShutdownHook] o.s.s.support.LifecycleObjectSupport : destroy called Process finished with exit code 0