通過spring statemmachine 自定義構建屬於自己的狀態機(兩種方式)

NO IMAGE

  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());
}
}