spring 状态机
前言:“状态机”见名知意,用状态去管理业务操作,打个比方:0~1岁(出生状态),1~3岁(认知状态),3~6岁(启蒙状态),6~22岁(学习状态),22~60(工作状态),60以后(退休状态),那么人一生成长经历则是(状态跳转):出生状态 -> 认知状态 -> 启蒙状态 -> 学习状态 -> 工作状态 -> 退休状态.
在每个状态中都会有不同的经历(事件),每个年龄就去干每个年龄的事情,背负这个年龄应该背负的责任,同时也享有这个年龄相应的乐趣(不同的状态去做不同的事情),直到离开这个世界(状态销毁)。
人的一生不可以倒退,但是:状态机可以,它可以在每个状态间互相跳转去做不同的事情,这样的好处:逻辑清晰、可以适当的控制并发、使整个事物更加通畅,好了,上代码:
1.新建状态机的辅助类:因为spring内部在redis中维护了一个状态机的hash表,所以必须接入redis
/*
* o(-"-)o
*
* CopyRight(C) 2011 GameRoot Inc.
*
*
*
*/
package com.qty.arena.helper.match.room; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.service.StateMachineService;
import org.springframework.stereotype.Component; import com.qty.arena.core.ObjectReference;
import com.qty.arena.room.match.statemachine.RoomMatchEvent;
import com.qty.arena.room.match.statemachine.RoomMatchState; /**
* 队伍状态机持久化辅助类
*
*
* @data 2018年1月31日 下午2:22:58
*/
@Component
public class RoomMatchStateMachineHelper { // private static final Logger LOGGER = LoggerFactory.getLogger(TeamStateMachineHelper.class); private static final ObjectReference<RoomMatchStateMachineHelper> ref = new ObjectReference<RoomMatchStateMachineHelper>(); /** 房间状态机参数传递通用DTO */
public static final String ROOM_ACTION_DELIVERY_DTO = "room_action_delivery_dto"; // @Autowired
// private StateMachinePersist<RoomState, RoomEvent, String> stateMachinePersist; @Autowired
private StateMachineService<RoomMatchState, RoomMatchEvent> roomMatchStateMachineService; @Autowired
private RedisTemplate<String, String> redisTemplate; @PostConstruct
void init() {
ref.set(this);
} public static RoomMatchStateMachineHelper getInstance() {
return ref.get();
} /**
* 获取状态机
*
* @param machineId
* 状态机编号
* @return
*/
public StateMachine<RoomMatchState, RoomMatchEvent> getStateMachine(String machineId) {
return roomMatchStateMachineService.acquireStateMachine(machineId);
} // /**
// * 存储状态
// *
// * @param machineId
// * 状态机编号
// * @throws Exception
// */
// public void save(String machineId) throws Exception {
// StateMachineContext<RoomState, RoomEvent> stateMachineContext = stateMachinePersist.read(machineId);
// stateMachinePersist.write(stateMachineContext, machineId);
// } /**
* 删除状态机
*
* @param machineId
* 状态机编号
*/
public void delete(String machineId) {
roomMatchStateMachineService.releaseStateMachine(machineId);
redisTemplate.delete("RedisRepositoryStateMachine:" + machineId);
} /**
* 普通状态转换事件
*
* @param machineId
* 状态机编号
* @param event
* 事件
*/
public StateMachine<RoomMatchState, RoomMatchEvent> sendEvent(String machineId, RoomMatchEvent event) {
StateMachine<RoomMatchState, RoomMatchEvent> stateMachine = getStateMachine(machineId);
if (stateMachine.sendEvent(event)) {
return stateMachine;
}
return null;
} /**
* 传参的状态转换事件
*
* @param machineId
* 状态机编号
* @param event
* 事件
* @param headerName
* 传递参数的Key
* @param object
* 传递的参数:对象
*/
public StateMachine<RoomMatchState, RoomMatchEvent> sendEvent(String machineId, RoomMatchEvent event, String headerName, Object object) {
StateMachine<RoomMatchState, RoomMatchEvent> stateMachine = getStateMachine(machineId);
Message<RoomMatchEvent> message = MessageBuilder
.withPayload(event)
.setHeader(headerName, object)
.build();
//传递参数的事件
if (stateMachine.sendEvent(message)) {
return stateMachine;
}
return null;
}
}
2.配置适配器
/*
* o(-"-)o
*
* CopyRight(C) 2011 GameRoot Inc.
*
*/
package com.qty.arena.room.custom.statemachine; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.data.redis.RedisPersistingStateMachineInterceptor;
import org.springframework.statemachine.data.redis.RedisStateMachineRepository;
import org.springframework.statemachine.persist.StateMachineRuntimePersister;
import org.springframework.statemachine.service.DefaultStateMachineService;
import org.springframework.statemachine.service.StateMachineService; import com.qty.arena.room.custom.statemachine.action.RoomCustomAlreadyDestroyEntryAction;
import com.qty.arena.room.custom.statemachine.action.RoomCustomAlreadySettlementEntryAction;
import com.qty.arena.room.custom.statemachine.action.RoomCustomCreateEntryAction;
import com.qty.arena.room.custom.statemachine.action.RoomCustomCreateLolInEntryAction;
import com.qty.arena.room.custom.statemachine.action.RoomCustomStartedEntryAction;
import com.qty.arena.room.custom.statemachine.action.RoomCustomVoteInEntryAction; /**
* 房间有限状态机适配器
*
*
* @data 2018年1月27日 上午10:30:42
*/
@EnableStateMachineFactory(name = "roomCustomStateMachineFactory")
public class RoomCustomStateMachineConfig extends EnumStateMachineConfigurerAdapter<RoomCustomState, RoomCustomEvent> { @Autowired
private RedisStateMachineRepository redisStateMachineRepository; @Autowired
private RoomCustomCreateEntryAction roomCustomCreateEntryAction; @Autowired
private RoomCustomCreateLolInEntryAction roomCustomCreateLolInEntryAction; @Autowired
private RoomCustomStartedEntryAction roomCustomStartedEntryAction; @Autowired
private RoomCustomVoteInEntryAction roomCustomVoteInEntryAction; @Autowired
private RoomCustomAlreadyDestroyEntryAction roomCustomAlreadyDestroyEntryAction; @Autowired
private RoomCustomAlreadySettlementEntryAction roomCustomAlreadySettlementEntryAction; @Bean("roomCustomStateMachinePersist")
public StateMachineRuntimePersister<RoomCustomState, RoomCustomEvent, String> stateMachinePersist() {
return new RedisPersistingStateMachineInterceptor<RoomCustomState, RoomCustomEvent, String>(
redisStateMachineRepository);
} @Bean("roomCustomStateMachineService")
public StateMachineService<RoomCustomState, RoomCustomEvent> stateMachineService(
StateMachineFactory<RoomCustomState, RoomCustomEvent> stateMachineFactory) {
return new DefaultStateMachineService<RoomCustomState, RoomCustomEvent>(stateMachineFactory,
stateMachinePersist());
} @Override
public void configure(StateMachineConfigurationConfigurer<RoomCustomState, RoomCustomEvent> config)
throws Exception {
config.withPersistence().runtimePersister(stateMachinePersist()); config.withMonitoring().monitor(new RoomCustomStateMachineMonitor());
} @Override
public void configure(StateMachineStateConfigurer<RoomCustomState, RoomCustomEvent> states) throws Exception {
states.withStates()
// 定义初始状态
.initial(RoomCustomState.UNCREATED)
// 定义状态机状态 /** 已创建db房间状态 */
.state(RoomCustomState.CREATED_DB_STATE, roomCustomCreateEntryAction, null) /** 创建Lol房间中状态 */
.state(RoomCustomState.CREATE_LOL_IN, roomCustomCreateLolInEntryAction, null) /** 已开局状态 */
.state(RoomCustomState.STARTED, roomCustomStartedEntryAction, null) /** 投票中状态 */
.state(RoomCustomState.VOTE_IN, roomCustomVoteInEntryAction, null) /** 自定义房间已结算状态 */
.state(RoomCustomState.ALREADY_SETTLEMENT, roomCustomAlreadySettlementEntryAction, null) /** 房间已销毁 */
.state(RoomCustomState.ALREADY_DESTROY, roomCustomAlreadyDestroyEntryAction, null); // .states(EnumSet.allOf(RoomState.class));
} @Override
public void configure(StateMachineTransitionConfigurer<RoomCustomState, RoomCustomEvent> transitions)
throws Exception { transitions // 初始化状态 -> 已创建 = 创建房间
.withExternal()
.source(RoomCustomState.UNCREATED)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.CREATE)
.and() // 已创建 -> 已销毁 = 退出(最后一人)
.withExternal()
.source(RoomCustomState.CREATED_DB_STATE)
.target(RoomCustomState.ALREADY_DESTROY)
.event(RoomCustomEvent.DESTROY_ROOM_CUSTOM)
.and() // 已创建 -> 已准备 = 全部准备
.withExternal()
.source(RoomCustomState.CREATED_DB_STATE)
.target(RoomCustomState.CREATE_LOL_IN)
.event(RoomCustomEvent.PREPARED_ALL)
.and() // 创建Lol房间中状态 -> 已创建 = 创建lol房间定时任务3分钟
.withExternal()
.source(RoomCustomState.CREATE_LOL_IN)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.CREATE_LOL_ROOM_TASK)
.and() // 创建lol房间中-> 已创建 = 退出
.withExternal()
.source(RoomCustomState.CREATE_LOL_IN)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.SIGN_OUT)
.and() // 创建lol房间中 -> 已开局 = 已创建LOL房间
.withExternal()
.source(RoomCustomState.CREATE_LOL_IN)
.target(RoomCustomState.STARTED)
.event(RoomCustomEvent.GAME_ROOM_HAS_BEEN_CREATED)
.and() // 已开局 -> 投票中 = 开始投票(6分钟)
.withExternal()
.source(RoomCustomState.STARTED)
.target(RoomCustomState.VOTE_IN)
.event(RoomCustomEvent.START_VOTE)
.and() // 投票中 -> 已创建 = 全部投票
.withExternal()
.source(RoomCustomState.VOTE_IN)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.ALL_VOTE)
.and() // 投票中 -> 已创建 = 全部投票
.withExternal()
.source(RoomCustomState.STARTED)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.ALL_VOTE)
.and() //投票中 -> 已创建 = 结算延时任务(2小时)
.withExternal()
.source(RoomCustomState.VOTE_IN)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.SETTLEMENT_DELAY_TASK)
.and() //投票中 -> 已结算 = 投票结算
.withExternal()
.source(RoomCustomState.VOTE_IN)
.target(RoomCustomState.ALREADY_SETTLEMENT)
.event(RoomCustomEvent.VOTE_SETTLEMENT)
.and() //投票中 -> 已结算 = 查询结算
.withExternal()
.source(RoomCustomState.VOTE_IN)
.target(RoomCustomState.ALREADY_SETTLEMENT)
.event(RoomCustomEvent.QUERY_SETTLEMENT)
.and() //投票中 -> 已结算 = 投票取消比赛(退还所有人蜜汁)
.withExternal()
.source(RoomCustomState.VOTE_IN)
.target(RoomCustomState.ALREADY_SETTLEMENT)
.event(RoomCustomEvent.VOTE_RETURN_MONEY)
.and() //已开局 -> 已结算 = 投票取消比赛(退还所有人蜜汁)
.withExternal()
.source(RoomCustomState.STARTED)
.target(RoomCustomState.ALREADY_SETTLEMENT)
.event(RoomCustomEvent.VOTE_RETURN_MONEY)
.and() //已结算 -> 已创建 = 全部投票
.withExternal()
.source(RoomCustomState.ALREADY_SETTLEMENT)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.ALL_VOTE)
.and() //已结算 -> 已创建 = 结算延时任务(2小时)
.withExternal()
.source(RoomCustomState.ALREADY_SETTLEMENT)
.target(RoomCustomState.CREATED_DB_STATE)
.event(RoomCustomEvent.SAVE_RECORD_DELAY_TASK)
.and()
;
}
}
3.Action
package com.qty.arena.room.custom.statemachine.action; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.action.Action;
import org.springframework.stereotype.Component; import com.qty.arena.dto.RoomCustomActionDeliveryDTO;
import com.qty.arena.helper.custom.room.RoomCustomCreateLolTaskHelper;
import com.qty.arena.helper.custom.room.RoomCustomSignOutHelper;
import com.qty.arena.helper.custom.room.RoomCustomStateMachineHelper;
import com.qty.arena.helper.custom.room.RoomCustomVoteReturnRoomHelper;
import com.qty.arena.room.custom.statemachine.RoomCustomEvent;
import com.qty.arena.room.custom.statemachine.RoomCustomState; /**
* 已创建db房间状态
*
* @author yanLong.Li
* @date 2018年11月10日 下午8:28:37
*/
@Component
public class RoomCustomCreateEntryAction implements Action<RoomCustomState, RoomCustomEvent> { @Autowired
private RoomCustomCreateLolTaskHelper roomCustomCreateLolTaskHelper; @Autowired
private RoomCustomSignOutHelper roomCustomSignOutHelper; @Autowired
private RoomCustomVoteReturnRoomHelper roomCustomVoteReturnRoomHelper; @Override
public void execute(StateContext<RoomCustomState, RoomCustomEvent> context) {
Object object = context.getMessageHeader(RoomCustomStateMachineHelper.ROOM_ACTION_DELIVERY_DTO);
if (!(object instanceof RoomCustomActionDeliveryDTO)) {
return;
}
RoomCustomEvent event = context.getEvent();
RoomCustomActionDeliveryDTO roomCustomActionDeliveryDTO = (RoomCustomActionDeliveryDTO) object;
logic(roomCustomActionDeliveryDTO, event);
} private void logic(RoomCustomActionDeliveryDTO roomCustomActionDeliveryDTO , RoomCustomEvent event) {
if(event == RoomCustomEvent.CREATE_LOL_ROOM_TASK) {
roomCustomCreateLolTaskHelper.createLolTask(roomCustomActionDeliveryDTO);
}/*else if(event == RoomCustomEvent.SETTLEMENT_DELAY_TASK) {
RoomCustomDTO roomCustomDTO = roomCustomActionDeliveryDTO.getRoomCustomDTO();
roomCustomHelper.settlementAndSaveRecord(roomCustomDTO);
}else if(event == RoomCustomEvent.SAVE_RECORD_DELAY_TASK) {
RoomCustomDTO roomCustomDTO = roomCustomActionDeliveryDTO.getRoomCustomDTO();
roomCustomHelper.saveRecord(roomCustomDTO);
}*/else if(event == RoomCustomEvent.SIGN_OUT) {
roomCustomSignOutHelper.preparedSignOut(roomCustomActionDeliveryDTO);
}else if(event == RoomCustomEvent.ALL_VOTE) {
roomCustomVoteReturnRoomHelper.execute(roomCustomActionDeliveryDTO);
}
}
}
4.演示调用
TeamMatchStateMachineHelper.getInstance().sendEvent(teamMatch.getStateMachineId(), TeamMatchEvent.CREATE
, TeamMatchStateMachineHelper.TEAM_ACTION_DELIVERY, TeamMatchActionDeliveryDTO.valueOf(teamMatch, arena.getId()));
spring 状态机的更多相关文章
- 彻底搞懂Spring状态机原理,实现订单与物流解耦
本文节选自<设计模式就该这样学> 1 状态模式的UML类图 状态模式的UML类图如下图所示. 2 使用状态模式实现登录状态自由切换 当我们在社区阅读文章时,如果觉得文章写得很好,我们就会评 ...
- 01-项目简介Springboot简介入门配置项目准备
总体课程主要分为4个阶段课程: ------------------------课程介绍------------------------ 01-项目简介Springboot简介入门配置项目准备02-M ...
- 花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘
本文所有内容均节选自<设计模式就该这样学> 序言 Design Patterns: Elements of Reusable Object-Oriented Software(以下简称&l ...
- Spring Boot 揭秘与实战(七) 实用技术篇 - StateMachine 状态机机制
文章目录 1. 环境依赖 2. 状态和事件 2.1. 状态枚举 2.2. 事件枚举 3. 状态机配置4. 状态监听器 3.1. 初始化状态机状态 3.2. 初始化状态迁移事件 5. 总结 6. 源代码 ...
- Spring Boot - StateMachine状态机
是Spring Boot提供的状态机的现成实现. 理论(有点像工作流) 需要定义一些状态的枚举,以及一些引起状态变化的事件的枚举. 每个状态可以对应的创建一个继承自org.springframewor ...
- 通过spring statemmachine 自定义构建属于自己的状态机(两种方式)
spring 的stateMachine 相对于当前的版本,还是比较新颖的,但是对于合适的业务场景,使用起来还是十分的方便的.但是对于官网提供的文档,讲解的是十分的精简,要想更深入的了解其内部架构,只 ...
- 使用Spring StateMachine框架实现状态机
spring statemachine刚出来不久,但是对于一些企业的大型应用的使用还是十分有借鉴意义的. 最近使用了下这个,感觉还是挺好的. 下面举个例子来说下吧: 创建一个Spring Boot的基 ...
- Spring web应用最大的败笔
第一篇 介绍下IOC DI Spring主要是业务层框架,现在已经发展成为一个完整JavaEE开发框架,它的主要特点是IoC DI和AOP等概念的融合,强项在面向切面AOP.推出之初因为Ioc/AOP ...
- Spring Boot 1.5.x 基础学习示例
一.为啥要学Spring Boot? 今年从原来.Net Team“被”转到了Java Team开始了微服务开发的工作,接触了Spring Boot这个新瓶装旧酒的技术,也初步了解了微服务架构.Spr ...
随机推荐
- 移动H5开发入门教程:12点webAPP前端开发经验
如果你是一名移动H5前端开发人员,25学堂的小编认为下面的分享的12点webAPP前端开发经验是你必须掌握的基础知识点.算是一篇移动H5开发入门教程吧! 1. viewport:也就是可视区域.对于桌 ...
- Qt ------ WAV 音频文件播放
1.用 QFile 打开 WAV 文件,读出文件头信息,看看是否符合音频播放设备的要求 QAudioDeviceInfo m_audioOutputDevice;//可以获取音频输出设备的信息,比如哪 ...
- indeed招聘
https://cn.indeed.com/%E5%B7%A5%E4%BD%9C-%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E5%85%AC%E5%8F%B8-%E5% ...
- Python的常用内置函数介绍
Python的常用内置函数介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.取绝对值(abs) #!/usr/bin/env python #_*_coding:utf-8_ ...
- 第一篇:打造专属开发工具Eclipse篇
第一篇:打造专属开发工具Eclipse篇 eclipse 优化 1.动画很酷,但如果可以的话,我总是在所有的工具中禁用动画.所以classic或者window classic主题是我最常用的主题 , ...
- 使用Arraylist将数组中元素随机均等乱序分为N个子数组
使用Arraylist将数组中元素随机均等乱序分为N个子数组 觉得有用的话,欢迎一起讨论相互学习~Follow Me 为了将数组中的元素 随机地 ,均等地, 不重复地 ,划分到N个子数组中 使用Arr ...
- centos7配置上网
过程请看图: just so so!
- python assert 断言语句的作用
python assert 断言语句的作用 assert语句的应用场景 使用assert语句是一个很好的习惯. 我们在编写代码的时候, 不知道程序会在什么时候崩溃, 与其让它在深度运行时崩溃, 不如预 ...
- ML—R常用多元统计分析包(持续更新中……)
基本的R包已经实现了传统多元统计的很多功能,然而CRNA的许多其它包提供了更深入的多元统计方法,下面要综述的包主要分为以下几个部分: 1) 多元数据可视化(Visualising multivaria ...
- Zookeeper笔记之命令行操作
$ZOOKEEPER_HOME/bin下的zkCli.sh进入命令行界面,使用help可查看支持的所有命令: 一.节点相关操作 create [-s] [-e] path data acl creat ...