spring-statemachine有限状态机学习

288 阅读2分钟

demo: www.cnblogs.com/xd502djj/p/…

  • maven中引入依赖
    <!--状态机-->
    <dependency>
        <groupId>org.springframework.statemachine</groupId>
        <artifactId>spring-statemachine-starter</artifactId>
        <version>2.5.0</version>
    </dependency>
   <!-- Spring State Machine Redis持久化 -->
    <dependency>
       <groupId>org.springframework.statemachine</groupId>
       <artifactId>spring-statemachine-redis</artifactId>
       <version>1.2.9.RELEASE</version>
    </dependency>
  • 定义状态和事件
public enum TestState {
    UNPAID,                 // 待支付
    WAITING_FOR_RECEIVE,    // 待收货
    DONE                    // 结束
}
public enum TestEvents {
    PAY,        // 支付
    RECEIVE     // 收货
}

配置 StatemachineConfigurer绑定状态与事件

**


import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.action.Action;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;

import java.util.EnumSet;

@Configuration
@EnableStateMachine(name = "StateMachineConfig")
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<TestState, TestEvents> {

    private Logger logger = LoggerFactory.getLogger(getClass());
    //定义初始状态
    @Override
    public void configure(StateMachineStateConfigurer<TestState, TestEvents> states)
            throws Exception {
        states.withStates()
              .initial(TestState.UNPAID)
              .states(EnumSet.allOf(TestState.class));
    }
    //状态转换过程 触发什么事件就转换为什么状态
    @Override
    public void configure(StateMachineTransitionConfigurer<TestState, TestEvents> transitions)
            throws Exception {
        transitions
            .withExternal()
                .source(TestState.UNPAID).target(TestState.WAITING_FOR_RECEIVE)
                .event(TestEvents.PAY)
                .and()
            .withExternal()
                .source(TestState.WAITING_FOR_RECEIVE).target(TestState.DONE)
                .event(TestEvents.RECEIVE);
    }
}

将事件监听触发与配置类进行配置:(EventListener) @OnTransition注解配置。它省去了原来事件监听器方法中各种if的判断,从而使代码显得更为简洁,具有更好的可读性。

@Component
@WithStateMachine(name = "StateMachineConfig")
public class EventListener {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @OnTransition(target = "UNPAID")
    public boolean create(Message<Order> order) {     // 创建订单逻辑
        logger.info("订单创建,待支付");
        return true;
    }

    @OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
    public boolean pay(Message<Order> order) {
        // 支付逻辑 从redis根据order 来进行处理
        logger.info("用户完成支付,待收货");
        return true;
    }

    @OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
    public boolean receive(Message<Order> order) {     //从redis中根据传入的order 来查询当前订单 并业务处理
        logger.info("用户已收货,订单完成");
        return true;
    }

}

持久化状态

//config配置类中
@Resource
private StateMachinePersist orderRedisStateMachineContextPersist;
/**
 * 持久化到redis中,在分布式系统中使用
 *
 * @return
 */ 
@Bean(name = "stateMachineRedisPersister")
public RedisStateMachinePersister<E, S> getRedisPersister() {
    return new RedisStateMachinePersister<>(orderRedisStateMachineContextPersist);
}
@Component
@RequiredArgsConstructor
public class OrderRedisStateMachineContextPersist implements StateMachinePersist<TestState, TestEvents, String> {
    private final RedisStateMachineContextRepository<TestState, TestEvents> redisStateMachineContextRepository;

    @Override
    public void write(StateMachineContext<TestState, TestEvents> context, String contextObj) throws Exception {
        redisStateMachineContextRepository.save(context, contextObj);
   }

    @Override
    public StateMachineContext<TestState, TestEvents> read(String contextObj) throws Exception {
        StateMachineContext<TestState, TestEvents> context = redisStateMachineContextRepository.getContext(contextObj);
        return context;
   }
}

测试

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
    public DemoApplication(StateMachine<TestState, TestEvents> stateMachine) {
        this.stateMachine = stateMachine;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    private final StateMachine<TestState, TestEvents> stateMachine;

    private final StateMachinePersister<TestState, TestEvents, String> stateMachineRedisPersister;


    @Override
    public void run(String... args) throws Exception {
        Order order=new Order("测试",0);
        // 使用 MessageBuilder 创建消息并设置负载和头信息
        Message message = MessageBuilder
                .withPayload(TestEvents.PAY)
                .setHeader("order", order)
                .build(); 
        //尝试恢复状态机状态
        stateMachineRedisPersister.restore(orderStateMachine, getContextObj(order));
        // 发送消息给状态机
        stateMachine.start();
        stateMachine.sendEvent(message);
        //执行成功则持久化状态机状态
        stateMachineRedisPersister.persist(orderStateMachine, getContextObj(order));
    }
}

888