zoukankan      html  css  js  c++  java
  • 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()));
  • 相关阅读:
    [adminitrative][archlinux][setfont] 设置console的字体大小
    [daily][archlinux][rsync] rsync
    [skill][msgpack] 初试msgpack库以及基本使用
    AWS之搭建深度学习主机
    AWS之SSH登录:使用 PuTTY 从 Windows 连接到 Linux 实例
    加拿大大学排名 by USNews
    Python多进程vs多线程
    Python之JSON使用
    Python之模块与包
    Android重打包+重新签名工具Apktool Box
  • 原文地址:https://www.cnblogs.com/li-yan-long/p/10247323.html
Copyright © 2011-2022 走看看