Stateless state machine–cola stateMachine

1. Introduction

cola stateMachine is a state developed by Alibaba master. It may be a simple tool developed in his spare time. This state is very different from spring stateMachine. It has a very excellent feature: Stateless.

It may be a bit contradictory to understand. A state machine is stateless, so why is it called a state machine? In fact, the state machine itself can be stateless, it is just a tool for managing state. Or call it an implementation of DSL grammar. It can help us better express the reverse expression of the document status. Just like XML, each configuration must meet the requirements and have a certain structure. Only if the configuration is correct will its attribute values take effect. So there is no need to literally understand whether a state machine has a state or not.

From the previous blog, it can be concluded that spring stateMachine has many disadvantages. The biggest disadvantage is that it is stateful, which leads us to need to add many new methods to reduce its memory consumption (custom state machine thread pool, The state machine can be reused, not a new object every time). At this time, the benefits of stateless state machines are reflected. The stateless state machine shows that it can be singletonized and that the state machine can be reused, which inherently solves the unnecessary memory consumption caused by statefulness.

This is not to say that spring stateMachine is not good, but that it is great. It’s a bit too good. Spring stateMachine has many excellent functions. However, these functions are not used at all in our daily development. As a result, spring stateMachine added many unnecessary things in order to implement the functions on ppt, making spring stateMachine appear too cumbersome. In this way, the advantages of cola stateMachine are more obvious. If you don’t know much about the state, you can read this article (https://blog.csdn.net/significantfrank/article/details/104996419) and you will feel the state In fact, it is not difficult at all, and it does not need to be as bulky as spring stateMachine.

The products produced by Alibaba must be high-quality products (not to blame Alibaba), but the products produced by Alibaba are usually endless (after all, others do not specialize in open source tools, and their time and energy are limited). Why is the cola stateMachine developed by Master Ali said that he developed it in his spare time? It is because he still has many scenarios that cannot be realized. We need to do secondary development based on our own business lines. Secondly, after reading the full text, it mainly focuses on the cola architecture, so I have such doubts.

2. Advantages

1. The code is simple and easy to learn, making it easy to do secondary development based on our business lines.

2. Stateless, reducing memory consumption, and threads are inherently safe.

3. Innate support matters

4. It will naturally throw exceptions by itself, and will not eat exceptions like spring stateMachine (of course exceptions can indeed be thrown through reflection).

5. The package is small. The unnecessary functions in spring stateMachine are abandoned. The function is relatively single, so the package is naturally small. At the same time, the waste of resources is reduced.

3. State machine basic model

1.State: state2.Event: event, the state is triggered by the event, causing changes3.Transition: flow, indicating from one state to Another state4.External Transition: External flow, the flow between two different states5.Internal Transition: Internal flow, the flow between the same state6.Condition: Condition, indicating whether it is allowed to reach a certain state7.Action: Action, what can be done after reaching a certain state8.StateMachine : State machine

4.Basic use


tateMachineBuilder builder = StateMachineBuilderFactory.create();
//external transition
builder.externalTransition()
?.from(States.STATE1)
?.to(States.STATE2)
.on(Events.EVENT1)
?.when(checkCondition())
?.perform(doAction());


//internal transition
builder.internalTransition()
?.within(States.STATE2)
?.on(Events.INTERNAL_EVENT)
?.when(checkCondition())
?.perform(doAction());


//external transitions
builder.externalTransitions()
?.fromAmong(States.STATE1, States.STATE2, States.STATE3)
?.to(States.STATE4)
.on(Events.EVENT4)
?.when(checkCondition())
?.perform(doAction());

builder.build(machineId);


StateMachine stateMachine = StateMachineFactory.get(machineId);
stateMachine.showStateMachine();

5. Custom development

When using cola stateMachine, there is a business scenario that the current state machine cannot implement, that is, when the current state and event are the same, but the target state is different, cola cannot implement it at this time. For example: when creating an outbound order for returns and sales, their events are all createBill, but the target status is different due to business differences, resulting in the target status being to be shipped out and to be picked off the shelf. Of course, you can handle this scenario through different events, such as definition: return out of stock operation, sales out of stock operation, no longer use the same event. Or handle it on the business code, but personally I think this is a compromise. I think the function of the checkCondition method has been relatively weakened. The judgment of checkCondition is just an if judgment in cola stateMachine. There are many if/else if/else judgments in real-world scenarios. In custom development, I enhanced this. In order to achieve this kind of judgment, I added a new type, the CHOOSE type. This type is an implementation of external state reversal. I am too lazy to do it based on the master’s code, so I simply added a new type. Otherwise, the great master’s code will have to be significantly modified.

Since the master’s source code is relatively simple, I only show part of the code implementation:

public class ChooseTransitionBuilderImpl<S, E, C> implements ChooseExternalTransitionBuilder<S, E, C>, ChooseFrom<S, E, C>, ChooseOn<S, E, C> {
    /**
     * Collection of state machines
     */
    final Map<S, State<S, E, C>> stateMap;
    /**
     * Source status
     */
    private State<S, E, C> source;
    /**
     * Target state
     */
    protected State<S, E, C> target;
    /**
     * State reversal entity
     */
    private Transition<S, E, C> transition;
    /**
     *Status reversal type
     */
    final TransitionType transitionType;

    private E event;

    public ChooseTransitionBuilderImpl(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) {
        this.stateMap = stateMap;
        this.transitionType = transitionType;
    }


    @Override
    public ChooseFrom<S, E, C> from(S stateId) {
        this.source = StateHelper.getState(stateMap, stateId);
        return this;
    }

    @Override
    public ChooseOn<S, E, C> on(E event) {
        this.event = event;
        return this;
    }

    @Override
    public ChooseOn<S, E, C> caseThen(Condition<C> condition, S stateId, Action<S, E, C> action) {
        target = StateHelper.getState(stateMap, stateId);
        transition = source.addTransitionByChoose(event, target, TransitionType.CHOOSE);
        transition.setAction(action);
        transition.setCondition(condition);
        return this;
    }

    @Override
    public void end(S stateId, Action<S, E, C> action) {
        target = StateHelper.getState(stateMap, stateId);
        transition = source.addTransitionByChoose(event, target, TransitionType.CHOOSE);
        transition.setAction(action);
        transition.setCondition(context -> true);
    }
}
 @Override
    public Transition<S, E, C> addTransitionByChoose(E event, State<S, E, C> target, TransitionType transitionType) {
        verifyChoose(event);
        Transition<S, E, C> newTransition = new TransitionImpl<>();
        newTransition.setSource(this);
        newTransition.setTarget(target);
        newTransition.setEvent(event);
        newTransition.setType(transitionType);
        Debugger.debug("Begin to add Choose Transition: " + newTransition);
        List<Transition<S, E, C>> transitions;
        if (chooseTransitions.containsKey(event)) {
            transitions = chooseTransitions.get(event);
        } else {
            transitions = new ArrayList<>();
        }
        transitions.add(newTransition);
        eventHashMap.put(event,transitionType);
        chooseTransitions.put(event, transitions);
        return newTransition;
    }

The specific implementation will be available on my gitee.

use

 StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
        builder.chooseExternalTransitions()
                .from(States.STATE1)
                .on(Events.EVENT1)
                .caseThen(checkCondition(false), States.STATE1, doAction())
                .caseThen(checkCondition(true), States.STATE3, doAction())
                .end(States.STATE4, doAction());

The master’s code is simple and easy to read, so it is very suitable for secondary development, which can be done according to the company’s business scenarios.

6. Specific implementation

gitee warehouse address

https://gitee.com/cola-demo-wx/wx-cola-demo

Reference link

https://blog.csdn.net/significantfrank/article/details/104996419