zoukankan      html  css  js  c++  java
  • Spring-statemachine fork一个region后不能进入join状态的问题

    Spring-statemachine版本:当前最新的1.2.3.RELEASE版本

    发现fork多个Region时,子状态全部完成后能够进入join状态。但是如果fork一个Region时Region完成后并不能进入join状态。状态机是StateMachineBuilder.builder()构建的。

    然后debug源码很久,发现状态机构建的逻辑是这样的:
    org.springframework.statemachine.config.AbstractStateMachineFactory

    public StateMachine<S, E> getStateMachine(UUID uuid, String machineId) {
        ...
        Collection<StateData<S, E>> stateDatas = popSameParents(stateStack);
        // stateDatas代表一个区域(Region。拥有相同的父状态)的状态集合
        int initialCount = getInitialCount(stateDatas); //获得一个region的初始化状态的数目
        Collection<Collection<StateData<S, E>>> regionsStateDatas = splitIntoRegions(stateDatas);
        Collection<TransitionData<S, E>> transitionsData = getTransitionData(iterator.hasNext(), stateDatas, stateMachineModel);
        
        if (initialCount > 1) { // 判断初始化状态数大于1才会通过RegionState创建子状态机
            for (Collection<StateData<S, E>> regionStateDatas : regionsStateDatas) {
                machine = buildMachine(machineMap, stateMap, holderMap, regionStateDatas, transitionsData, resolveBeanFactory(stateMachineModel),
                    contextEvents, defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(stateMachineModel),
                    resolveTaskScheduler(stateMachineModel), machineId, null, stateMachineModel);
                regionStack.push(new MachineStackItem<S, E>(machine));
            }
        
            Collection<Region<S, E>> regions = new ArrayList<Region<S, E>>();
            while (!regionStack.isEmpty()) {
                MachineStackItem<S, E> pop = regionStack.pop();
                regions.add(pop.machine);
            }
            S parent = (S)peek.getParent();
            // 创建类型为RegionState的状态
            RegionState<S, E> rstate = buildRegionStateInternal(parent, regions, null, stateData != null ? stateData.getEntryActions() : null,
                stateData != null ? stateData.getExitActions() : null, new DefaultPseudoState<S, E>(PseudoStateKind.INITIAL));
            if (stateData != null) {
                stateMap.put(stateData.getState(), rstate);
            } else {
                // TODO: don't like that we create a last machine here
                Collection<State<S, E>> states = new ArrayList<State<S, E>>();
                states.add(rstate);
                Transition<S, E> initialTransition = new InitialTransition<S, E>(rstate);
                // 把RegionState转变成ObjectStateMachine子状态机
                StateMachine<S, E> m = buildStateMachineInternal(states, new ArrayList<Transition<S, E>>(), rstate, initialTransition,
                    null, defaultExtendedState, null, contextEvents, resolveBeanFactory(stateMachineModel), resolveTaskExecutor(stateMachineModel),
                    resolveTaskScheduler(stateMachineModel), beanName,
                    machineId != null ? machineId : stateMachineModel.getConfigurationData().getMachineId(),
                    uuid, stateMachineModel);
                machine = m;
            }
        } else { // 如果没有初始化状态或只有一个初始化状态,就构建一个普通的ObjectStateMachine子状态机
            machine = buildMachine(machineMap, stateMap, holderMap, stateDatas, transitionsData, resolveBeanFactory(stateMachineModel), contextEvents,
                defaultExtendedState, stateMachineModel.getTransitionsData(), resolveTaskExecutor(stateMachineModel), resolveTaskScheduler(stateMachineModel),
                machineId, uuid, stateMachineModel);
            if (peek.isInitial() || (!peek.isInitial() && !machineMap.containsKey(peek.getParent()))) {
                machineMap.put(peek.getParent(), machine);
            }
        }        
        ...
    }
    

    从上面的源码可以看出:当子状态机只有一个初始化状态时,不会通过RegionState去创建子状态机。

    在同一个类中有个buildMachine方法如下,增加一段"else if"代码后解决问题:

    private StateMachine<S, E> buildMachine(Map<Object, StateMachine<S, E>> machineMap, Map<S, State<S, E>> stateMap,
    			Map<S, StateHolder<S, E>> holderMap, Collection<StateData<S, E>> stateDatas, Collection<TransitionData<S, E>> transitionsData,
    			BeanFactory beanFactory, Boolean contextEvents, DefaultExtendedState defaultExtendedState,
    			TransitionsData<S, E> stateMachineTransitions, TaskExecutor taskExecutor, TaskScheduler taskScheduler, String machineId,
    			UUID uuid, StateMachineModel<S, E> stateMachineModel)
    			
    	...
    	// 如果当前状态是虚拟状态,而且类型是JOIN
    	} else if (stateData.getPseudoStateKind() == PseudoStateKind.JOIN) {
    		S s = stateData.getState();
    		List<S> list = stateMachineTransitions.getJoins().get(s);
    		List<State<S, E>> joins = new ArrayList<State<S,E>>();
    
    		// if join source is a regionstate, get
    		// it's end states from regions
    		if (list.size() == 1) {
    			State<S, E> ss1 = stateMap.get(list.get(0));
    			// 判断状态是RegionState时,才会把子状态机的终结状态加入到joins中
    			if (ss1 instanceof RegionState) { 
    				Collection<Region<S, E>> regions = ((RegionState<S, E>)ss1).getRegions();
    				for (Region<S, E> r : regions) {
    					Collection<State<S, E>> ss2 = r.getStates();
    					for (State<S, E> ss3 : ss2) {
    						if (ss3.getPseudoState() != null && ss3.getPseudoState().getKind() == PseudoStateKind.END) {
    							joins.add(ss3);
    							continue;
    						}
    					}
    				}
    			// 下面这个else if是我加的代码
    			// 判断如果当前状态是子状态机状态类型
    			// 也把子状态的终结状态加入到joins中
    			} else if (ss1 instanceof StateMachineState) {
    			    Collection<State<S, E>> subStates = ((StateMachineState) ss1).getSubmachine().getStates();
    			    for (State<S, E> subState : subStates) {
    			        if (subState.getPseudoState() != null && subState.getPseudoState().getKind() == PseudoStateKind.END) {
    			            joins.add(subState);
    			        }
    			    }
                }
    		} else {
    			for (S fs : list) {
    				joins.add(stateMap.get(fs));
    			}
    		}
    
    		List<JoinStateData<S, E>> joinTargets = new ArrayList<JoinStateData<S, E>>();
    		Collection<TransitionData<S, E>> transitions = stateMachineTransitions.getTransitions();
    		for (TransitionData<S, E> tt : transitions) {
    			if (tt.getSource() == s) {
    				StateHolder<S, E> holder = new StateHolder<S, E>(stateMap.get(tt.getTarget()));
    				if (holder.getState() == null) {
    					holderMap.put(tt.getTarget(), holder);
    				}
    				joinTargets.add(new JoinStateData<S, E>(holder, tt.getGuard()));
    			}
    		}
    		JoinPseudoState<S, E> pseudoState = new JoinPseudoState<S, E>(joins, joinTargets);
    
    		state = buildStateInternal(stateData.getState(), stateData.getDeferred(), stateData.getEntryActions(),
    				stateData.getExitActions(), stateData.getStateActions(), pseudoState, stateMachineModel);
    		states.add(state);
    		stateMap.put(stateData.getState(), state);
    	}
    	...
    }
    

    这样就能解决Fork+Join+单个Region无法join的问题了

    Github issue: https://github.com/spring-projects/spring-statemachine/issues/337

  • 相关阅读:
    三数之和
    罗马数字与整数
    Oracle 开启或关闭归档
    Oracle RMAN scripts to delete archivelog
    Oracle check TBS usage
    Oracle kill locked sessions
    场景9 深入RAC运行原理
    场景7 Data Guard
    场景4 Data Warehouse Management 数据仓库
    场景5 Performance Management
  • 原文地址:https://www.cnblogs.com/lanhj/p/6617254.html
Copyright © 2011-2022 走看看