通过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());
}
}
通过spring statemmachine 自定义构建属于自己的状态机(两种方式)的更多相关文章
- XFire构建服务端Service的两种方式(转)
XFire构建服务端service的两种方式,一是用xfire构建,二是和spring集成构建. 一,xifre构建,确保把xfire的jar包导入到工程中或classpath. 1,service的 ...
- XFire构建服务端Service的两种方式
1.原声构建: 2.集成spring构建 http://blog.csdn.net/carefree31441/article/details/4000436XFire构建服务端Service的两种方 ...
- spring boot项目获取application配置文件参数的两种方式
前言:了解过spring boot这个技术的,应该知道spring boot的核心配置文件application.properties,当然也可以通过注解自定义配置文件**.properties的信息 ...
- iOS开发小技巧--自定义带有占位文字的TextView(两种方式)
自定义控件注意或框架注意:自己暴露在外面的属性,一定要重写setter,保证外界与内部的交互性 一.方案一:通过drawRect:方法将文字画到textView中,监听文字改变用的是通知中心(代理也可 ...
- 两种方式,花五分钟就能构建一个 Spring Boot 应用
前言 Spring Boot 的好处自然不必多说,对于想要从事 Java 工作的朋友们来说,可谓是必学的技能. 在我看来,它的优势就是多快好省. 功能多,很多常用的能力都有集成: 接入快,简单的几行代 ...
- Spring Boot 定义系统启动任务,你会几种方式?
在 Servlet/Jsp 项目中,如果涉及到系统任务,例如在项目启动阶段要做一些数据初始化操作,这些操作有一个共同的特点,只在项目启动时进行,以后都不再执行,这里,容易想到web基础中的三大组件( ...
- Spring Boot2 系列教程(十五)定义系统启动任务的两种方式
在 Servlet/Jsp 项目中,如果涉及到系统任务,例如在项目启动阶段要做一些数据初始化操作,这些操作有一个共同的特点,只在项目启动时进行,以后都不再执行,这里,容易想到web基础中的三大组件( ...
- Spring集成Quartz框架的两种方式。
可参考:https://blog.csdn.net/yk614294861/article/details/84324603 1.使用Spring与Quarta配置作业得两种方式: a.方式一,Met ...
- egg.js 通过 form 和 ajax 两种方式上传文件并自定义目录和文件名
egg.js 通过 form 和 ajax 两种方式上传文件并自定义目录和文件名 评论:10 · 阅读:8437· 喜欢:0 一.需求 二.CSRF 校验 三.通过 form 表单上传文件 四.通过 ...
随机推荐
- 解决黑群晖"抱歉,您所指定的页面不存在"-记一次黑群晖修复案例
起因 搞了一个usb外接硬盘准备备份数,刚好看到群晖有个工具软件"USB Copy". 安装后设置拷贝docker文件夹,然后就悲剧了,nas主页抛出提示 一开始也是直接网上搜索标 ...
- 在.NET Core中使用Channel(三)
到目前为止,我们一直在使用所谓的"Unbounded"通道.你会注意到,当我们创建通道时,我们这样做: var myChannel = Channel.CreateUnbounde ...
- Redis的sentinel(哨兵)部署
1.准备文件 1.解压redis-4.0.1.tar.gz的redis文件 2.新建目录 redis-cluster以及子目录 master-6379 slave-7000 slave-7001 3. ...
- 笔记:学习go语言的网络基础库,并尝试搭一个简易Web框架
在日常的 web 开发中,后端人员常基于现有的 web 框架进行开发.但单纯会用框架总感觉不太踏实,所以有空的时候还是看看这些框架是怎么实现的会比较好,万一要排查问题也快一些. 最近在学习 go 语言 ...
- LeetCode141-环形链表检测
题目 给定一个链表,判断链表中是否有环. 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置 ...
- wpf 在不同DPI下如何在DrawingVisual中画出清晰的图形
环境Win10 VS2017 .Net Framework4.7.1 本文仅讨论在DrawingVisual中进行的画图. WPF单位,系统DPI,显示器DPI三者的定义及关系 WPF单位:一 ...
- Python找对称数——纪念第一次自主编写代码
2021-01-17 题目: [问题描述]已知10个四位数输出所有对称数及个数 n,例如1221.2332都是对称数[输入形式]10个四位数,以空格分隔开[输出形式]输入的四位数中的所有对称数,对称数 ...
- Java开发手册之编程规约
时隔一年多,再次开始更新博客,各位粉丝们久等了.大家是不是以为我像大多数开发者一样三分钟热度,坚持了一年半载就放弃了,其实不是.在过去的一年时间我学习了<Java编程思想>这本书,因为都是 ...
- [Usaco2007 Feb]Cow Party
题目描述 农场有N(1≤N≤1000)个牛棚,每个牛棚都有1只奶牛要参加在X牛棚举行的奶牛派对.共有M(1≤M≤100000)条单向路连接着牛棚,第i条踣需要Ti的时间来通过.牛们都很懒,所以不管是前 ...
- 干电池升压IC
1, 干电池升压IC 升压输出3V,3,3V,5V等3V-5V可调 2, 单节锂电池升压IC 升压输出4.2 ...