状态机StateMachine使用小记

概要:Spring Statemachine

状态机之所以强大,是因为始终保证行为是一致的,这使得调试相对容易。这是因为在机器启动时,操作规则是不可更改的。其思想是,应用程序可能存在有限数量的状态,某些预定义的触发器可以将应用程序从一种状态转移到另一种状态。这样的触发器可以基于事件或计时器。
在应用程序之外定义高级逻辑,然后依靠状态机来管理状态要容易得多。您可以通过发送事件、侦听更改或请求当前状态来与状态机交互。

官网地址:https://projects.spring.io/spring-statemachine/

  • 依赖

    <dependency>
        <groupId>org.springframework.statemachinegroupId>
        <artifactId>spring-statemachine-coreartifactId>
        <version>2.1.3.RELEASEversion>
    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.messaging.Message;
    import org.springframework.messaging.support.MessageBuilder;
    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);
                Message<OrderEvent> message = MessageBuilder.withPayload(event).setHeader("order", order).build();
                result = orderStateMachine.sendEvent(message);
                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 {
           
    
        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) {
           
                // TODO ....
            }
    
        }
    
    }
    
    
  • 监听状态机

    package com.example.statemachine.listener;
    
    import com.example.statemachine.bean.Order;
    import com.example.statemachine.constant.OrderEvent;
    import com.example.statemachine.constant.OrderStatus;
    import org.springframework.messaging.Message;
    import org.springframework.statemachine.annotation.OnTransition;
    import org.springframework.statemachine.annotation.WithStateMachine;
    import org.springframework.stereotype.Component;
    
    import java.util.Optional;
    
    /**
     * @author liuteng
     * 状态机监听器
     */
    @Component
    @WithStateMachine(name = "orderStateMachine")
    public class OrderStatusListener {
           
    
        private static final String FORMAT = "事件: %s  单号: %s, 状态: %s";
    
        @OnTransition(source = "PAID", target = "SEND")
        public boolean sendTransition(Message<OrderEvent> message) {
           
            Order order = (Order) message.getHeaders().get("order");
            Optional.ofNullable(order).ifPresent(ord -> {
           
                order.setStatus(OrderStatus.SEND.getCode());
                System.out.println(String.format(FORMAT, message.getPayload().getEventCode(), ord.getOid(), ord.getStatus()));
                // TODO 持久化
            });
            return true;
        }
    
        @OnTransition(source = "SEND", target = "RECEIVE")
        public boolean receiveTransition(Message<OrderEvent> message) {
           
            Order order = (Order) message.getHeaders().get("order");
            Optional.ofNullable(order).ifPresent(ord -> {
           
                order.setStatus(OrderStatus.RECEIVE.getCode());
                System.out.println(String.format(FORMAT, message.getPayload().getEventCode(), ord.getOid(), ord.getStatus()));
                // TODO 持久化
            });
            return true;
        }
    
        @OnTransition(source = "RECEIVE", target = "RETURN")
        public boolean returnTransition(Message<OrderEvent> message){
           
            Order order = (Order) message.getHeaders().get("order");
            Optional.ofNullable(order).ifPresent(ord -> {
           
                order.setStatus(OrderStatus.RETURN.getCode());
                System.out.println(String.format(FORMAT, message.getPayload().getEventCode(), ord.getOid(), ord.getStatus()));
                // TODO 持久化
            });
            return true;
        }
    }
    
    
  • 结果

      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: 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
    

你可能感兴趣的:(SpringBoot,状态机,spring)