坚持和恢复Spring Statemachine中的当前状态

时间:2015-06-02 12:01:50

标签: persistence state spring-statemachine

我将Spring Statemachine引入现有项目,希望合并并澄清我们的业务逻辑。我们有各种具有互连状态的JPA实体,并且在将持久状态设置为现有状态机的当前状态时遇到了一些麻烦。

我使用StateMachineFactory为每个实体实例创建一个新的StateMachine实例。我将StateMachine的当前状态存储在一个单独的字段中,以便Hibernate持久化,理想情况下需要将持久字段的值与StateMachine同步。我的问题是如何在Spring Statemachine中实现这一目标。

@Entity
@EntityListeners(MyEntityListener.class)
public class MyEntity {

    @Column
    private MyState internalState; // Using AttributeConverter

    @Transient
    private StateMachine<MyState, Event> stateMachine;

}
public class MyEntityListener {

    @PostLoad
    public void postLoad(MyEntity entity) {
        // TODO Set StateMachine's current state to entity's internal state
    );

}
  1. 一种方法可能是定义局部转换以将初始状态移动到持久状态。然后我可以进行条件检查以找到与本地转换相关联的事件,这会将源状态移动到目标状态。这对我来说似乎有些混乱,我希望尽可能保持状态机的配置。

  2. 我无法看到如何通过公共API设置StateMachine的当前状态而不进行转换,因此我探索的另一种方法是将StateMachine实例包装为暴露以下内容方法(因为它方便默认范围):

  3. package org.springframework.statemachine.support;
    
    public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSupport<S, E> implements StateMachine<S, E>, StateMachineAccess<S, E> {
    
        void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit, StateMachine<S, E> stateMachine)
    
    }
    
    package org.springframework.statemachine.support;
    
    public class MyStateMachineWrapper<S, E> {
    
        private AbstractStateMachine<S, E> stateMachine;
    
        public MyStateMachineWrapper(StateMachine<S, E> stateMachine) {
            if (stateMachine instanceof AbstractStateMachine) {
                this.stateMachine = (AbstractStateMachine<S, E>)stateMachine;
            } else {
                throw new IllegalArgumentException("Provided StateMachine is not a valid type");
            }
        }
    
        public void setCurrentState(S status) {
            stateMachine.setCurrentState(findState(status), null, null, false, stateMachine);
        }
    
        private State<S, E> findState(S status) {
            for (State<S, E> state : stateMachine.getStates()) {
                if (state.getId() == status) {
                    return state;
                }
            }
    
            throw new IllegalArgumentException("Specified status does not equate to valid State");
        }
    }
    

    然后我可以将以下代码放入 MyEntityListener.postLoad

    MyStateMachineWrapper<MyState, Event> myStateMachineWrapper = new MyStateMachineWrapper<>(entity.getStateMachine());
    myStateMachineWrapper.setCurrentState(entity.getInternalState());
    

    上述方法似乎运行良好,但我无法想象这是设想的工作方式。当然,有一个更简洁的方法来实现这个目标,或者项目可能还不够成熟并且还没有包含这个功能吗?

    感谢您的任何想法和意见。

1 个答案:

答案 0 :(得分:2)

我已经清理了上面的选项#2,将包装类更改为utils类。为了清楚起见,这种方法利用了具有默认访问器的setCurrentState方法,因此这可能最终成为一个脆弱的解决方案。

package org.springframework.statemachine.support;

public abstract class MyStateMachineUtils extends StateMachineUtils {

    public static <S, E> void setCurrentState(StateMachine<S, E> stateMachine, S state) {
        if (stateMachine instanceof AbstractStateMachine) {
            setCurrentState((AbstractStateMachine<S, E>)stateMachine, state);
        } else {
            throw new IllegalArgumentException("Provided StateMachine is not a valid type");
        }
    }

    public static <S, E> void setCurrentState(AbstractStateMachine<S, E> stateMachine, S state) {
        stateMachine.setCurrentState(findState(stateMachine, state), null, null, false, stateMachine);
    }

    private static <S, E> State<S, E> findState(AbstractStateMachine<S, E> stateMachine, S stateId) {
        for (State<S, E> state : stateMachine.getStates()) {
            if (state.getId() == stateId) {
                return state;
            }
        }

        throw new IllegalArgumentException("Specified State ID is not valid");
    }
}

然后可以很好地使用它:

MyStateMachineUtils.setCurrentState(entity.getStateMachine(), entity.getInternalState());