spring statemachine 多个状态机实践

最近在做老系统升级改造,为了解决原来流程复杂,代码冗杂的情况,计划引入状态机框架来改造,为更好理解,也为记录下自己的学习过程,计划写总结博文。

状态机spring statemachine 概述

Spring Statemachine是应用程序开发人员在Spring应用程序中使用状态机概念的框架
Spring Statemachine旨在提供以下功能:
1. 易于使用的扁平单级状态机,用于简单的使用案例。
2. 分层状态机结构,以简化复杂的状态配置。
3. 状态机区域提供更复杂的状态配置。
4. 使用触发器,转换,警卫和操作。
5. 键入安全配置适配器。
6. 生成器模式,用于在Spring Application上下文之外使用的简单实例化通常用例的食谱
7. 基于Zookeeper的分布式状态机
8. 状态机事件监听器。
9. UML Eclipse Papyrus建模。
10. 将计算机配置存储在永久存储中。
11. Spring IOC集成将bean与状态机关联起来。

状态机功能强大,因为行为始终保证一致,使调试相对容易。这是因为操作规则是在机器启动时写成的。这个想法是你的应用程序可能存在于有限数量的状态中,某些预定义的触发器可以将你的应用程序从一个状态转移到另一个状态。此类触发器可以基于事件或计时器。

在应用程序之外定义高级逻辑然后依靠状态机来管理状态要容易得多。您可以通过发送事件,侦听更改或仅请求当前状态来与状态机进行交互。

快速开始

已经写过状态机的简单启动,状态流转的例子,但实际应用过程不可能只用到一个machine,需多个machine处理对象流转。

下面的实践有以下特色:
1、不同线程启用不同statemachine实例处理
2、用工厂模式创建statemachine,且用StateMachinePersist根据recruit对象不同状态反序列化statemachine
3、 用message 给OnTransition注解的方法传递对象

@Configuration
//@EnableStateMachine(name = "ddd")
@Scope("prototype")
@EnableStateMachineFactory(name = "recruitStateMachineFactory")
public class Config1 extends EnumStateMachineConfigurerAdapter<States, Events> {
    /**订单状态机ID*/
    public static final String orderStateMachineId = "recruitStateMachineId";
    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states)
            throws Exception {
        states
                .withStates()
                .initial(States.STATE1)
                .states(EnumSet.allOf(States.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
            throws Exception {
        transitions
                .withExternal()
                .source(States.STATE1).target(States.STATE2)
                .event(Events.EVENT1)
                .and()
                .withExternal()
                .source(States.STATE2).target(States.STATE1)
                .event(Events.EVENT2)
       }

    @Bean
    public StateMachinePersister<States, Events, Recruit> persister(){
        return new DefaultStateMachinePersister<States, Events, Recruit>(new StateMachinePersist<States, Events, Recruit>() {
            @Override
            public void write(StateMachineContext<States, Events> context, Recruit order) throws Exception {
                //此处并没有进行持久化操作
                //order.setStatus(context.getState());
            }
@Override
public StateMachineContext<States, Events> read(Recruit order) throws Exception {
                //此处直接获取order中的状态,其实并没有进行持久化读取操作
                StateMachineContext<States, Events> result =new DefaultStateMachineContext<States, Events>(order.getStates(), null, null, null, null, orderStateMachineId);
                return result;
            }
        });
    }
 }

状态转换

@WithStateMachine(name = "recruitStateMachineId")
public class MyBean {
    @OnTransition(source="STATE2" ,target = "STATE1")
   public void toState1(Message message) {
        Recruit recruit = (Recruit) message.getHeaders().get("recruit");
        System.out.println("toState1" +Thread.currentThread().toString());
    }

    @OnTransition(source="" ,target = "STATE1")
    public void initState() {

        System.out.println("toState1"+Thread.currentThread().toString());
    }

    @OnTransition(source="STATE1",target = "STATE2")
  public  void toState2() throws Exception {
      System.out.println("toState2"+Thread.currentThread().toString());
      //throw new Exception();

    }
}
@RestController
public class MyApp {
    ThreadLocal<StateMachine> stateMachineThreadLocal  = new ThreadLocal<StateMachine>();

    @Autowired
            @Qualifier("recruitStateMachineFactory" )
    StateMachineFactory<States, Events> stateMachineFactory;

    @Autowired
    private StateMachinePersister<States, Events,Recruit> persister;
    @RequestMapping("/hello")
    void doSignals() {
        System.out.println("start before");
       Recruit recruit = new Recruit();
        StateMachine stateMachinet = getStateMachine(recruit);
        System.out.println("dosignals stateMachinet hashcode "+stateMachinet.hashCode()+"  recruit hashcode is "+recruit.hashCode());
        stateMachinet.sendEvent(Events.EVENT1);
        stateMachinet.sendEvent(Events.EVENT2);
    }
    private StateMachine getStateMachine(Recruit recruit){
        StateMachine machine = stateMachineThreadLocal.get();
        if (null == machine){
            machine = stateMachineFactory.getStateMachine("recruitStateMachineId");
        }
        try {
            machine.start();
            persister.restore(machine,recruit);
        } catch (Exception e) {
            //e.printStackTrace();
        }
        return machine;
    }

    void sendEvent(Events events,Recruit recruit){
        Message message = MessageBuilder.withPayload(events).setHeader("recruit", recruit).build();
       StateMachine stateMachine = getStateMachine(recruit);
       stateMachine.sendEvent(message);
    }

    @RequestMapping("/sendEvent1")
    void sendEvent(){
        Recruit recruit = new Recruit();
        recruit.setStates(States.STATE1);
        StateMachine stateMachine = getStateMachine(recruit);
        stateMachine.sendEvent(Events.EVENT1);

    }
    @RequestMapping("/sendEvent2")
    void sendEvent2(){
        Recruit recruit = new Recruit();
        recruit.setStates(States.STATE2);
        StateMachine stateMachine = getStateMachine(recruit);
        stateMachine.sendEvent(Events.EVENT2);

    }
}

总结

解决了如何处理多用户多对象场景如何启用状态机的例子,但只有状态机简单的状态迁移,状态机配置可以有多种方法,下一篇文章分析各种配置的不同用法

ChoiceTransitionConfigurer<\S,E> withChoice()
ChoiceTransitionConfigurer<\S,E> withChoice()
EntryTransitionConfigurer<\S,E> withEntry()
ExitTransitionConfigurer<\S,E> withExit()

ExternalTransitionConfigurer<\S,E> withExternal()

ForkTransitionConfigurer<\S,E> withFork()

HistoryTransitionConfigurer<\S,E> withHistory()

InternalTransitionConfigurer<\S,E> withInternal()

JoinTransitionConfigurer<\S,E> withJoin()

JunctionTransitionConfigurer<\S,\E> withJunction()

LocalTransitionConfigurer<\S,E> withLocal()

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值