前言:“状态机”见名知意,用状态去管理业务操作,打个比方: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 状态机的更多相关文章

  1. 彻底搞懂Spring状态机原理,实现订单与物流解耦

    本文节选自<设计模式就该这样学> 1 状态模式的UML类图 状态模式的UML类图如下图所示. 2 使用状态模式实现登录状态自由切换 当我们在社区阅读文章时,如果觉得文章写得很好,我们就会评 ...

  2. 01-项目简介Springboot简介入门配置项目准备

    总体课程主要分为4个阶段课程: ------------------------课程介绍------------------------ 01-项目简介Springboot简介入门配置项目准备02-M ...

  3. 花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘

    本文所有内容均节选自<设计模式就该这样学> 序言 Design Patterns: Elements of Reusable Object-Oriented Software(以下简称&l ...

  4. Spring Boot 揭秘与实战(七) 实用技术篇 - StateMachine 状态机机制

    文章目录 1. 环境依赖 2. 状态和事件 2.1. 状态枚举 2.2. 事件枚举 3. 状态机配置4. 状态监听器 3.1. 初始化状态机状态 3.2. 初始化状态迁移事件 5. 总结 6. 源代码 ...

  5. Spring Boot - StateMachine状态机

    是Spring Boot提供的状态机的现成实现. 理论(有点像工作流) 需要定义一些状态的枚举,以及一些引起状态变化的事件的枚举. 每个状态可以对应的创建一个继承自org.springframewor ...

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

    spring 的stateMachine 相对于当前的版本,还是比较新颖的,但是对于合适的业务场景,使用起来还是十分的方便的.但是对于官网提供的文档,讲解的是十分的精简,要想更深入的了解其内部架构,只 ...

  7. 使用Spring StateMachine框架实现状态机

    spring statemachine刚出来不久,但是对于一些企业的大型应用的使用还是十分有借鉴意义的. 最近使用了下这个,感觉还是挺好的. 下面举个例子来说下吧: 创建一个Spring Boot的基 ...

  8. Spring web应用最大的败笔

    第一篇 介绍下IOC DI Spring主要是业务层框架,现在已经发展成为一个完整JavaEE开发框架,它的主要特点是IoC DI和AOP等概念的融合,强项在面向切面AOP.推出之初因为Ioc/AOP ...

  9. Spring Boot 1.5.x 基础学习示例

    一.为啥要学Spring Boot? 今年从原来.Net Team“被”转到了Java Team开始了微服务开发的工作,接触了Spring Boot这个新瓶装旧酒的技术,也初步了解了微服务架构.Spr ...

随机推荐

  1. 解决 django 博客归档 “Are time zone definitions for your database and pytz installed?”的错误

    修改 project 中的settings 文件,问题解决! # USE_TZ = True USE_TZ = False # LANGUAGE_CODE = 'en-us' LANGUAGE_COD ...

  2. OpenStack 计算服务 Nova计算节点部署(八)

    如果使用vmware虚拟机进行部署,需要开启虚拟化:如果是服务器需要在bios上开启. nova计算节点IP是192.168.137.12 环境准备 安装时间同步 yum install ntpdat ...

  3. 样本标准差分母为何是n-1

    sklearn实战-乳腺癌细胞数据挖掘 https://study.163.com/course/introduction.htm?courseId=1005269003&utm_campai ...

  4. Hadoop基础--统计商家id的标签数案例分析

    Hadoop基础--统计商家id的标签数案例分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.项目需求 将“temptags.txt”中的数据进行分析,统计出商家id的评论标 ...

  5. 命令卸载ie11

    管理员运行cmd. 执行命令FORFILES /P %WINDIR%\servicing\Packages /M Microsoft-Windows-InternetExplorer-*11.*.mu ...

  6. C语言复习---获取最大公约数(辗转相除法和更相减损法)

    源自:百度百科 辗转相除法 辗转相除法:辗转相除法是求两个自然数的最大公约数的一种方法,也叫欧几里德算法. 例如,求(,): ∵ ÷=(余319) ∴(,)=(,): ∵ ÷=(余58) ∴(,)=( ...

  7. AngularJS 启程三

    <!DOCTYPE html> <html lang="zh_CN"> <head> <title>字数小例子</title& ...

  8. html5 canvas旋转+缩放

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. [转载]JavaScript 运行机制详解:再谈Event Loop

    https://app.yinxiang.com/shard/s8/sh/b72fe246-a89d-434b-85f0-a36420849b84/59bad790bdcf6b0a66b8b93d5e ...

  10. 第7月第11天 AVAsset

    1. An AVAsset defines the collective properties of the tracks that comprise the asset. (You can acce ...