Ala*_*lan 5 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;
}
Run Code Online (Sandbox Code Playgroud)
public class MyEntityListener {
@PostLoad
public void postLoad(MyEntity entity) {
// TODO Set StateMachine's current state to entity's internal state
);
}
Run Code Online (Sandbox Code Playgroud)
一种方法可以是定义局部转换以将初始状态移动到持久状态.然后我可以进行条件检查以找到与本地转换相关联的事件,这会将源状态移动到目标状态.这对我来说似乎有些混乱,我希望尽可能保持状态机的配置.
我无法看到如何在不通过转换的情况下通过公共API设置StateMachine的当前状态,因此我探索的另一种方法是将StateMachine实例包装为公开以下方法(因为它是方便的默认范围):
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)
}
Run Code Online (Sandbox Code Playgroud)
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");
}
}
Run Code Online (Sandbox Code Playgroud)
然后我可以将以下代码抛入MyEntityListener.postLoad:
MyStateMachineWrapper<MyState, Event> myStateMachineWrapper = new MyStateMachineWrapper<>(entity.getStateMachine());
myStateMachineWrapper.setCurrentState(entity.getInternalState());
Run Code Online (Sandbox Code Playgroud)
上面的方法似乎工作正常,但我无法想象这是如何设想工作.当然有一个更简洁的方法来实现这一点,或者项目可能还不够成熟,还不包括这个功能?
感谢您的任何想法和意见.
我已经清理了上面的选项 #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");
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以很好地使用它,如下所示:
MyStateMachineUtils.setCurrentState(entity.getStateMachine(), entity.getInternalState());
Run Code Online (Sandbox Code Playgroud)