spring 状态机
Posted 明天会更好
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring 状态机相关的知识,希望对你有一定的参考价值。
前言:“状态机”见名知意,用状态去管理业务操作,打个比方:0~1岁(出生状态),1~3岁(认知状态),3~6岁(启蒙状态),6~22岁(学习状态),22~60(工作状态),60以后(退休状态),那么人一生成长经历则是(状态跳转):出生状态 -> 认知状态 -> 启蒙状态 -> 学习状态 -> 工作状态 -> 退休状态.
在每个状态中都会有不同的经历(事件),每个年龄就去干每个年龄的事情,背负这个年龄应该背负的责任,同时也享有这个年龄相应的乐趣(不同的状态去做不同的事情),直到离开这个世界(状态销毁)。
人的一生不可以倒退,但是:状态机可以,它可以在每个状态间互相跳转去做不同的事情,这样的好处:逻辑清晰、可以适当的控制并发、使整个事物更加通畅,好了,上代码:
1.新建状态机的辅助类:因为spring内部在redis中维护了一个状态机的hash表,所以必须接入redis
/* * o(-"-)o * * CopyRight(C) 2011 GameRoot Inc. * * Author: ma.chao * * QQ: 402879660 * * Mail: [email protected] */ 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; /** * 队伍状态机持久化辅助类 * * @author [email protected] * * @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. * * Author: ma.chao * * QQ: 402879660 * * Mail: [email protected] */ 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; /** * 房间有限状态机适配器 * * @author [email protected] * * @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 状态机的主要内容,如果未能解决你的问题,请参考以下文章
用状态机控制业务状态扭转 Hello Spring StateMachine
spring框架中spring-statement-core状态机源码分析
Spring StateMachine,教你快速实现一个状态机
Spring StateMachine,教你快速实现一个状态机