通过spring statemmachine 自定义构建属于自己的状态机(两种方式)

  spring 的stateMachine 相对于当前的版本,还是比较新颖的,但是对于合适的业务场景,使用起来还是十分的方便的。但是对于官网提供的文档,讲解的是十分的精简,要想更深入的了解其内部架构,只有不断的测试,查看内部源码的实现,能够大幅度的给你更大的启发!在今天,小编将介绍如何不通过使用官网的方式构建状态机,实现自己的业务逻辑:

 首先,这里为了配置方便构建,创建业务所需要的entity配置类,

    

package statemachine.v2.entity;

public class ConfigEntity {
    /**
     * 业务 id 号
     */
    private int id;
    /**
     * 源状态
     */
    private String source;
    /**
     * 目标状态
     */
    private String target;
    /**
     * 触发的事件
     */
    private String event;
    /**
     * 备注信息
     */
    private String info;

    /**
     * 业务类型
     */
    private int type;

    public ConfigEntity(int id, String source, String target, String event, String info, int type) {
        this.id = id;
        this.source = source;
        this.target = target;
        this.event = event;
        this.info = info;
        this.type = type;
    }

    public ConfigEntity(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target;
    }

    public String getEvent() {
        return event;
    }

    public void setEvent(String event) {
        this.event = event;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "ConfigEntity{" +
                "id=" + id +
                ", source='" + source + '\'' +
                ", target='" + target + '\'' +
                ", event='" + event + '\'' +
                ", info='" + info + '\'' +
                ", type=" + type +
                '}';
    }
}
   然后构建自己的配置信息类,构造相关的配置信息。

  

package statemachine.v2.config;

import org.springframework.statemachine.config.model.*;
import org.springframework.statemachine.state.PseudoStateKind;
import statemachine.v2.entity.ConfigEntity;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 配置必要的配置信息
 */
public class SSMConfig {
    private static final HashSet<String> states = new HashSet<String>();
    private static final HashSet<ConfigEntity> configEntities = new HashSet<ConfigEntity>();

    public static final StateData<String, String> initState = new StateData<String, String>("初始状态" ,true);
    public static final StateData<String, String> endState = new StateData<String, String>("结束状态");

    public static HashSet <String> getStates() {
        return states;
    }

    public static HashSet <ConfigEntity> getConfigEntities() {
        return configEntities;
    }

    /**
     * 配置的构造方法
     */
    static {
        //构造配置信息列表,这个可以根据业务实际需求设置,可自定义
        Set<ConfigEntity> configEntities = new HashSet <ConfigEntity>(Arrays.asList(
                new ConfigEntity(1,"初始状态","状态1","事件1","",001),
                new ConfigEntity(1,"状态1","状态2","事件2","",001),
                new ConfigEntity(1,"状态2","状态1","事件3","",001),
                new ConfigEntity(1,"状态2","结束状态","事件4","",001)));
        for(ConfigEntity configEntity : configEntities){
            states.add(configEntity.getSource());
            configEntities.add(configEntity);
        }
    }


    /**
     * 构建 ConfigurationData,在这一步也可以构建为分布式的,如基于zookeeper
     * @return
     */
    public static ConfigurationData<String,String> getConfigurationData(){
        ConfigurationData<String, String> configurationData = new ConfigurationData<String, String>();
        return configurationData;
    }

    /**
     * 构建状态数据信息对象, 这一步是构建状态机的各个状态字段,用于装载状态机的状态转换之间的状态配置
     * @return
     */
    public static StatesData<String,String> getStatesData(){
        HashSet<StateData<String, String>> stateDatas = new HashSet<StateData<String, String>>();
        //初始状态
        initState.setPseudoStateKind(PseudoStateKind.INITIAL);
        stateDatas.add(initState);

        //结束状态
        endState.setEnd(true);
        endState.setPseudoStateKind(PseudoStateKind.END);
        stateDatas.add(endState);

        //其他状态加载
        for (String state: states){
            StateData<String, String> stateData = new StateData<String, String>(state);
            stateDatas.add(stateData);
        }

        //构建
        StatesData<String, String> statesData = new StatesData<String, String>(stateDatas);

        return statesData;
    }

    /**
     * 状态事物转换的流程配置
     * @return
     */
    public static TransitionsData<String,String> getTransitionsData(){
        HashSet<TransitionData<String,String>> transitionDatas = new HashSet<TransitionData<String,String>>();
        for (ConfigEntity configEntity : configEntities ){

            TransitionData<String,String> transitionData = new TransitionData<String,String>(configEntity.getSource(),
                    configEntity.getTarget(),
                    configEntity.getEvent()
            );
            transitionDatas.add(transitionData);

        }
        TransitionsData<String,String> transitionsData = new TransitionsData<String,String>(transitionDatas);

        return transitionsData;
    }

}

  最后通过以上的信息,构建状态机的类,通过该类来创建状态机,获取状态机的实例:这里提供两种方式构建,大家可以根据自己的业务自行选择:

   

package statemachine.v2.config;


import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.ObjectStateMachineFactory;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.statemachine.config.model.ConfigurationData;
import org.springframework.statemachine.config.model.DefaultStateMachineModel;
import org.springframework.statemachine.config.model.StatesData;
import org.springframework.statemachine.config.model.TransitionsData;
import statemachine.v2.entity.ConfigEntity;

import java.util.Collection;
import java.util.HashSet;

public class MakeStateMachine {
    /**
     * 构建状态机,方式一
     * @return
     * @throws Exception
     */
    public static StateMachine<String,String> createStateMachine() throws Exception {
        ConfigurationData<String, String> configData = SSMConfig.getConfigurationData();
        StatesData<String, String> statesData = SSMConfig.getStatesData();
        TransitionsData<String, String> transitionsData = SSMConfig.getTransitionsData();
        DefaultStateMachineModel<String,String> machineModel = new DefaultStateMachineModel<String, String>(configData,statesData,transitionsData);
        ObjectStateMachineFactory<String, String> machineFactory = new ObjectStateMachineFactory<String, String>(machineModel);
        StateMachine<String, String> stateMachine  = machineFactory.getStateMachine();
        //添加状态机的监听器,自行实现
//        stateMachine.addStateListener(new StateMachineListener <String, String>() {});

        //添加状态机的拦截器,自行实现内部接口即可
//        stateMachine.getStateMachineAccessor()
//                         .withRegion()
//                         .addStateMachineInterceptor(new StateMachineInterceptor <String, String>() {});
        return stateMachine;
    }

    /**
     * 构建状态机,方式二
     */
    public  StateMachine<String,String> getStateMachine() throws Exception {
        StateMachineBuilder.Builder<String,String> builder = StateMachineBuilder.builder();
        builder.configureConfiguration()
                .withConfiguration()
                //添加状态机监听器
//                .listener(new StateMachineListener <String, String>() {})
                .beanFactory(new StaticListableBeanFactory());//添加构建bean的工厂类,可以自行实现,这里是使用系统的默认

        Collection<ConfigEntity> data = SSMConfig.getConfigEntities();
        HashSet<String> states = new HashSet<String>();
        for (ConfigEntity configEntity : data) {
            states.add(configEntity.getTarget());
            builder.configureTransitions()
                    .withExternal()
                    .source(configEntity.getSource())
                    .target(configEntity.getTarget())
                    .event(configEntity.getEvent());
        }

        builder.configureStates()
                .withStates()
                .initial(SSMConfig.initState.getState())
                .state(SSMConfig.initState.getState())
                .end(SSMConfig.endState.getState())
                .states(states);

        return builder.build();
    }

}

  使用的话,可以像之前的版本方式使用即可,详细可以参考:初识状态机

 

public class Main {

    public static void main(String[] args) throws Exception {

        StateMachine<String, String> stateMachine = MakeStateMachine.createStateMachine();
        //方式一, 发送触发事件,改变状态
        stateMachine.sendEvent("事件1");

        //方式二, 发送触发事件,改变状态
        stateMachine.sendEvent(MessageBuilder
                .withPayload("事件1")
                .setHeader("testStateMachine", "测试头部") // header中可以存放相关数据信息,
                // 这些信息,在执行过程中,可以在监听器和拦截器中获取到,通过拦截器你可以在做额外的一些事情
                .build());
        
    }
}






posted @ 2017-08-13 14:06  zhou_jun  阅读(1936)  评论(0编辑  收藏  举报