美文网首页
COLA下的cola-statemachine状态机

COLA下的cola-statemachine状态机

作者: holmes000 | 来源:发表于2021-01-14 16:53 被阅读0次

    相比Spring statemachine状态机等的复杂,功能多;我们更需要常用的功能,简单使用,所以这类就显得不简洁;再看cola-statemachine相比就是小巧、无状态、简单、轻量、性能极高的状态机DSL实现,解决业务中的状态流转问题。
    github:
    https://github.com/alibaba/COLA/tree/master/cola-components/cola-component-statemachine

    概念:
    State:状态

    Event:事件,状态由事件触发,引起变化

    Transition:流转,表示从一个状态到另一个状态

    External Transition:外部流转,两个不同状态之间的流转

    Internal Transition:内部流转,同一个状态之间的流转

    Condition:条件,表示是否允许到达某个状态

    Action:动作,到达某个状态之后,可以做什么

    StateMachine:状态机

    外部过程描述:起始状态STATE1,结束状态STATE2,当发生EVENT1时执行状态转移,当满足checkCondition()时,执行doAction,执行成功则返回状态STATE2,否则返回STATE1。

    public class StateMachineTest {
    
        static String MACHINE_ID = "TestStateMachine";
    
        static enum States {
            STATE1, STATE2, STATE3, STATE4
        }
    
        static enum Events {
            EVENT1, EVENT2, EVENT3, EVENT4, INTERNAL_EVENT
        }
    
        static class Context{
            String operator = "frank";
            String entityId = "123465";
        }
    
        @Test
        public void testExternalNormal(){
            // 第一步:生成一个状态机builder
            StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
            // 第二步:设置一个外部状态转移类型的builder,并设置from\to\on\when\perform
            builder.externalTransition()
                    .from(States.STATE1)
                    .to(States.STATE2)
                    .on(Events.EVENT1)
                    .when(checkCondition())
                    .perform(doAction()); //这个action 我们可以按自己所需修改,比如这种Action<R,T> service的方法Service::method
     
            // 第三步:设置状态机的id和ready,并在StateMachineFactory中的stateMachineMap进行注册
            StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID);
            // 第四步:触发状态机
            States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context());
            Assert.assertEquals(States.STATE2, target);
        }
    }
    

    源码分析:这里只是简单介绍,整个流转的链路,因为具体的代码还是要根据自己的知识储备理解;
    第一步:生成一个状态机builder
    new com.alibaba.cola.statemachine.builder.StateMachineBuilderImpl

        /**
         * StateMap is the same with stateMachine, as the core of state machine is holding reference to states.
         */
        private final Map<S, State< S, E, C>> stateMap = new ConcurrentHashMap<>();
        private final StateMachineImpl<S, E, C> stateMachine = new StateMachineImpl<>(stateMap);
    

    第二步:设置一个外部状态转移类型的builder,并设置from\to\on\when\perform

    @Override
        public ExternalTransitionBuilder<S, E, C> externalTransition() {
            return new TransitionBuilderImpl<>(stateMap, TransitionType.EXTERNAL);
        }
    

    TransitionBuilderImpl为多实现接口实现类,这个设计加上不同接口的唯一方法实现,可以让from to ,按DSL方式运行

    class TransitionBuilderImpl<S,E,C> implements ExternalTransitionBuilder<S,E,C>, InternalTransitionBuilder<S,E,C>, From<S,E,C>, On<S,E,C>, To<S,E,C> {
    
    
    image.png

    上述构建就是一个状态流转的过程

    class TransitionBuilderImpl<S,E,C> implements ExternalTransitionBuilder<S,E,C>, InternalTransitionBuilder<S,E,C>, From<S,E,C>, On<S,E,C>, To<S,E,C> {
        //状态机
        final Map<S, State<S, E, C>> stateMap;
        //原状态
        private State<S, E, C> source;
        //目标状态
        protected State<S, E, C> target;
        //该具体做事流转
        private Transition<S, E, C> transition;
         //流转类型
        final TransitionType transitionType;
    ...
        // 此时只是把from的state新增到stateMap中,返回结果赋给本地变量source
        @Override
        public From<S, E, C> from(S stateId) {
            source = StateHelper.getState(stateMap, stateId);
            return this;
        }
     
        // 此时只是把to的state新增到stateMap中,返回结果赋给本地变量target
        @Override
        public To<S, E, C> to(S stateId) {
            target = StateHelper.getState(stateMap, stateId);
            return this;
        }
      //所以ON是在Form和to后面执行,因为它用本流程中的source,向来源state中加入Transition
      //Transition是一个具体做事的流转,其中包含事件,目标状态和流转类型
      //看下面源码就是一个事件对应Transition
      @Override
        public On<S, E, C> on(E event) {
            transition = source.addTransition(event, target, transitionType);
            return this;
        }
    //该执行流转的条件
    @Override
        public When<S, E, C> when(Condition<C> condition) {
            transition.setCondition(condition);
            return this;
        }
    //设置transition的action
     @Override
        public void perform(Action<S, E, C> action) {
            transition.setAction(action);
        }
    
    ...
    }
    

    第三步:
    builder.build(MACHINE_ID) 此步就是状态机已构建完成,一般直接@Bean注入,使用时直接调用

    
    public class StateMachineBuilderImpl<S, E, C> implements StateMachineBuilder<S, E, C> {
     
    ...
     
        private final StateMachineImpl<S, E, C> stateMachine = new StateMachineImpl<>(stateMap);
     
    ...
     
        // 设置状态机的id和ready,并在StateMachineFactory中的stateMachineMap进行注册
        @Override
        public StateMachine<S, E, C> build(String machineId) {
            stateMachine.setMachineId(machineId);
            stateMachine.setReady(true);
            StateMachineFactory.register(stateMachine);
            return stateMachine;
        }
     
    }
    

    第四步:States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context()); 业务具体使用时,这个方法入参是原状态和事件和action的入参,这个就按上面配置的状态机进行流转;from to on when perform

    public class StateMachineImpl<S,E,C> implements StateMachine<S, E, C> {
    
        private String machineId;
    
        private final Map<S, State<S,E,C>> stateMap;
    
        private boolean ready;
    
        public StateMachineImpl(Map<S, State< S, E, C>> stateMap){
            this.stateMap = stateMap;
        }
    
        public S fireEvent(S sourceStateId, E event, C ctx){
            isReady();
            State sourceState = getState(sourceStateId);
            return doTransition(sourceState, event, ctx).getId();
        }
    
        private State<S, E, C> doTransition(State sourceState, E event, C ctx) {
            //根据原状态和事件获取流转transition
            Optional<Transition<S,E,C>> transition = sourceState.getTransition(event);
            if(transition.isPresent()){
                //ctx为执行入参
                return transition.get().transit(ctx);
            }
            Debugger.debug("There is no Transition for " + event);
            return sourceState;
    
    

    Transition是具体做事的流转

    /**
     * TransitionImpl。
     *
     * This should be designed to be immutable, so that there is no thread-safe risk
     *
     * @author Frank Zhang
     * @date 2020-02-07 10:32 PM
     */
    public class TransitionImpl<S,E,C> implements Transition<S,E,C> {
    
        private State<S, E, C> source;
    
        private State<S, E, C> target;
    
        private E event;
    
        private Condition<C> condition;
    
        private Action<S,E,C> action;
    
        private TransitionType type = TransitionType.EXTERNAL;
        
    ...
     @Override
        public State<S, E, C> transit(C ctx) {
            Debugger.debug("Do transition: "+this);
            this.verify();
            if(condition == null || condition.isSatisfied(ctx)){
                if(action != null){
                    action.execute(source.getId(), target.getId(), event, ctx);
                }
                return target;
            }
    
            Debugger.debug("Condition is not satisfied, stay at the "+source+" state ");
            return source;
        }
    ...
        @Override
        public final String toString() {
            return source + "-[" + event.toString() +", "+type+"]->" + target;
        }
    
        @Override
        public boolean equals(Object anObject){
            if(anObject instanceof Transition){
                Transition other = (Transition)anObject;
                if(this.event.equals(other.getEvent())
                        && this.source.equals(other.getSource())
                        && this.target.equals(other.getTarget())){
                    return true;
                }
            }
            return false;
        }
    
        @Override
        public void verify() {
            if(type== TransitionType.INTERNAL && source != target) {
                throw new StateMachineException(String.format("Internal transition source state '%s' " +
                        "and target state '%s' must be same.", source, target));
            }
        }
    

    State是整个流转中状态类

    public interface State<S,E,C> extends Visitable{
    
        /**
         * Gets the state identifier.
         *
         * @return the state identifiers
         */
        S getId();
    
        /**
         * Add transition to the state
         * @param event the event of the Transition
         * @param target the target of the transition
         * @return
         */
        Transition<S,E,C> addTransition(E event, State<S, E, C> target, TransitionType transitionType);
    
        Optional<Transition<S,E,C>> getTransition(E event);
    
        Collection<Transition<S,E,C>> getTransitions();
    
    }
    
    public class StateImpl<S,E,C> implements State<S,E,C> {
        protected final S stateId;
        private HashMap<E, Transition<S, E,C>> transitions = new HashMap<>();
    
        StateImpl(S stateId){
            this.stateId = stateId;
        }
    
        @Override
        public Transition<S, E, C> addTransition(E event, State<S,E,C> target, TransitionType transitionType) {
            Transition<S, E, C> newTransition = new TransitionImpl<>();
            newTransition.setSource(this);
            newTransition.setTarget(target);
            newTransition.setEvent(event);
            newTransition.setType(transitionType);
    
            Debugger.debug("Begin to add new transition: "+ newTransition);
            verify(event, newTransition);
            transitions.put(event, newTransition);
            return newTransition;
        }
     /**
         * @param event
         * @param newTransition
         */
        private void verify(E event, Transition<S,E,C> newTransition) {
            Transition existingTransition = transitions.get(event);
            if(existingTransition != null){
                if(existingTransition.equals(newTransition)){
                    throw new StateMachineException(existingTransition+" already Exist, you can not add another one");
                }
            }
        }
    

    最后用层级展示下源码的设计:存储下来类似树形分支
    第一维度:状态
    第二维度:原状态 对应 事件
    第三维度:事件对应具体流转


    image.png

    相关文章

      网友评论

          本文标题:COLA下的cola-statemachine状态机

          本文链接:https://www.haomeiwen.com/subject/vqrvaktx.html