狀態機StateMachine使用小記

概要: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
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章