通過spring statemmachine 自定義構建屬於自己的狀態機(兩種方式)
阿新 • • 發佈:2019-01-09
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());
}
}