squirrel-foundation状态机的使用细节

来源:互联网 发布:js创建list 编辑:程序博客网 时间:2024/05/16 23:40

上一篇文章介绍了stateless4j、spring-statemachine以及squirrel-foundation三款状态机引擎的实现原理,以及我为何选择squirrel-foundation作为解决方案。本文主要介绍一下项目中如何使用squirrel-foundation的一些细节以及如何与spring进行集成。在阅读本文前,建议先阅读官方的使用手册。 

squirrel-foundation状态机的使用细节

date: 2017-06-19 15:50:18

生命周期

状态机创建过程

  • StateMachine: StateMachine实例由StateMachineBuilder创建不被共享,对于使用annotation方式(或fluent api)定义的StateMachine,StateMachine实例即根据此定义创建,相应的action也由本实例执行,与spring的集成最终要的就是讲spring的bean实例注入给由builder创建的状态机实例;
  • StateMachineBuilder: 本质上是由StateMachineBuilderFactory创建的动态代理。被代理的StateMachineBuilder默认实现为StateMachineBuilderImpl,内部描述了状态机实例创建细节包括State、Event、Context类型信息、constructor等,同时也包含了StateMachine的一些全局共享资源包括StateConverter、EventConverter、MvelScriptManager等。StateMachineBuilder可被复用,使用中可被实现为singleton;
  • StateMachineBuilderFactory: 为StateMachineBuilder创建的动态代理实例;

事件处理过程

  • 状态正常迁移 
    TransitionBegin–(exit->transition->entry)–>TransitionComplete–>TransitionEnd
  • 状态迁移异常 
    TransitionBegin–(exit->transition->entry)–>TransitionException–>TransitionEnd
  • 状态迁移事件拒绝 
    TransitionBegin–>TransitionDeclined–>TransitionEnd

statemachine lifecycle

spring集成

从statemachine的生命流程上可以看到,StateMachineBuilder可以单例方式由spring container管理,而stateMachine的instance的生命周期伴随着请求(或业务)。 
从这两点出发,集成spring需要完成两件事: 
* (1).通过Spring创建StateMachineBuilder实例; 
* (2).业务函数中通过(1)的StateMachineBuilder实例创建StateMachine实例,并向StateMachine暴露SpringApplicationContext;

泛型参数+覆盖默认构造函数隐藏StateMachineBuilder创建细节,实现ApplicationContextAware接口,接受applicationContext注入,并注入给stateMachine实例。

public abstract class AbstractStateMachineEngine<T extends UntypedStateMachine> implements ApplicationContextAware {    protected UntypedStateMachineBuilder stateMachineBuilder = null;    @SuppressWarnings("unchecked")    public AbstractStateMachineEngine() {        //识别泛型参数        Class<T> genericType = (Class<T>)GenericTypeResolver.resolveTypeArgument(getClass(),            AbstractStateMachineEngine.class);        stateMachineBuilder = StateMachineBuilderFactory.create(genericType, ApplicationContext.class);    }    //注入applicationContext,并在创建StateMachine实例时注入    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        this.applicationContext = applicationContext;    }    //delegate fire    public void fire(int rmaId, State initialState, Trigger trigger, StateMachineContext context) {        T stateMachine = stateMachineBuilder.newUntypedStateMachine(                            initialState                            //暂时开启debug进行日志trace                            StateMachineConfiguration.create().enableDebugMode(true).enableAutoStart(true),                            //注入applicationContext                            applicationContext);        stateMachine.fire(trigger, context);    }    ...}@Serviceclass DiscountRefundStateMachineEngine extends AbstractStateMachineEngine<DiscountRefundStateMachine> {}@Servicepublic class ReturnGoodsStateMachineEngine extends AbstractStateMachineEngine<ReturnGoodsStateMachine> {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

StateMachine定义,接受SpringContext注入

@StateMachineParameters(stateType = State.class, eventType = Trigger.class,    //StateMachineContext 自定义上下文,用来传递数据    contextType = StateMachineContext.class)@States({    @State(name = "PENDING", initialState = true),    @State(name = "CONFIRMING"),    @State(name = "REJECTED"),    @State(name = "REFUND_APPROVING"),    @State(name = "REFUND_APPROVED"),    @State(name = "REFUND_FINISHED")})@Transitions({    @Transit(from = "PENDING", to = "CONFIRMING", on = "APPLY_CONFIRM",        callMethod = "doSomething"),    @Transit(from = "CONFIRMING", to = "REJECTED", on = "REJECT"),    @Transit(from = "CONFIRMING", to = "REFUND_APPROVING", on = "APPLY_APPROVED"),    @Transit(from = "REFUND_APPROVING", to = "REFUND_APPROVED", on = "REFUND_APPROVED"),    @Transit(from = "REFUND_APPROVED", to = "REFUND_FINISHED", on = "REFUND_FINISH_CONFIRM")})public class DiscountRefundStateMachine extends AbstractUntypedStateMachine {    protected ApplicationContext applicationContext;    //定义构造函数接受ApplicationContext注入([参看New State Machine Instance](http://hekailiang.github.io/squirrel/))    public DiscountRefundStateMachine(ApplicationContext applicationContext) {        this.applicationContext = applicationContext;    }    public void doSomething(State fromState, State toState, Trigger event,                         StateMachineContext stateMachineContext) {         DemoBean demoBean = this.applicationContext.get("demoBean");         //do something    }    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

状态持久化

从StateMachine的事件响应流程中可以看到,TransitionBegin–(exit->transition->entry)–>TransitionComplete–>TransitionEnd,在TransitionComplete发生一个状态已从source迁移到了target状态,所以我选择了在这个时间点进行了状态的持久化(没有选择TransitionEnd做持久化,因为某些场景在持久化完成后还会存在一些外部动作的触发,例如通知第三方系统当前状态已完成变更)。

public class DiscountRefundStateMachine extends AbstractUntypedStateMachine {    ..    @Override    protected void afterTransitionCompleted(Object fromState, Object toState, Object event, Object context) {        if (context instanceof StateMachineContext && toState instanceof State) {            StateMachineContext stateMachineContext = (StateMachineContext)context;            //从上下文中获取需要持久化的数据,例如订单ID等            Rma rma = stateMachineContext.get(MessageKeyEnum.RMA);            //持久化            rma.setStatus((State)toState);            this.applicationContext.get("rmaRepository").updateRma(rma);        } else {            throw new Exception("type not support, context expect " + StateMachineContext.class.getSimpleName() + ", actually "                    + context.getClass().getSimpleName() + ", state expect " + State.class.getSimpleName()                    + ", actually "                    + toState.getClass().getSimpleName());        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

分布式锁+事务

由于StateMachine实例不是由Spring容器创建,所以这个过程中无法通过注解方式开启事务(Spring没有机会去创建事务代理),我采用了编程式事务,在AbstractStateMachineEngine的fire函数中隐式的实现。 
AbstractStateMachineEngine#fire

public abstract class AbstractStateMachineEngine<T extends UntypedStateMachine> implements ApplicationContextAware {    ...    public void fire(int rmaId, State initialState, Trigger trigger, StateMachineContext context) {        JedisLock jedisLock = jedisLockFactory.buildLock(rmaId);        //争用分布式锁        if (jedisLock.tryLock()) {            try {                T stateMachine = stateMachineBuilder.newUntypedStateMachine(                                    initialState                                    //暂时开启debug进行日志trace                                    StateMachineConfiguration.create().enableDebugMode(true).enableAutoStart(true),                                    //注入applicationContext                                    applicationContext);                DataSourceTransactionManager transactionManager = applicationContext.get("transactionManager")                DefaultTransactionDefinition def = new DefaultTransactionDefinition();                def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);                TransactionStatus status = transactionManager.getTransaction(def);                try {                    stateMachine.fire(trigger, context)                    transactionManager.commit(status);                } catch (Exception ex) {                    transactionManager.rollback(status);                    throw ex;                }            } finally {                jedisLock.release();            }        }         ...    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

文章转载自:http://blog.csdn.net/gkqcz/article/details/73641749