概要: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