我的多用户环境也有同样的问题。食谱的概念并没有真正起作用。对所有请求仅使用一个状态机不是线程安全的。我以 PersistStateMachineHandler 的风格编写了自己的类,但不是使用给定的 StateMachine,而是使用给定的 StateMachineFactory。
public class PersistentStateMachineHandler<S, T> {
private final StateMachineFactory<S, T> stateMachineFactory;
private final PersistingStateChangeInterceptor<S, T> interceptor = new PersistingStateChangeInterceptor<>();
private final CompositePersistStateChangeListener<S, T> listeners = new CompositePersistStateChangeListener<>();
public PersistentStateMachineHandler(StateMachineFactory<S, T> stateMachineFactory) {
this.stateMachineFactory = stateMachineFactory;
}
public void addPersistentStateChangeListener(PersistentStateChangeListener<S, T> persistentStateChangeListener) {
listeners.register(persistentStateChangeListener);
}
public boolean handleEventWithState(Map<Object, Object> variables, S state, T event) {
StateMachine<S, T> stateMachine = stateMachineFactory.getStateMachine();
stateMachine.getStateMachineAccessor().doWithAllRegions(function -> function.addStateMachineInterceptor(interceptor));
if (state == null) {
state = stateMachine.getInitialState().getId();
}
ExtendedState extendedState = new DefaultExtendedState(variables);
List<StateMachineAccess<S, T>> withAllRegions = stateMachine.getStateMachineAccessor().withAllRegions();
for (StateMachineAccess<S, T> a : withAllRegions) {
a.resetStateMachine(new DefaultStateMachineContext<S, T>(state, null, null, extendedState));
}
stateMachine.start();
return stateMachine.sendEvent(event);
}
public interface PersistentStateChangeListener<S, T> {
void persist(State<S, T> state, Message<T> message, Transition<S, T> transition, StateMachine<S, T> stateMachine);
}
private class PersistingStateChangeInterceptor<X, Y> extends StateMachineInterceptorAdapter<S, T> {
@Override
public void preStateChange(State<S, T> state, Message<T> message, Transition<S, T> transition, StateMachine<S, T> stateMachine) {
listeners.persist(state, message, transition, stateMachine);
}
}
private class CompositePersistStateChangeListener<X, Y> extends AbstractCompositeListener<PersistentStateChangeListener<S, T>> implements
PersistentStateChangeListener<S, T> {
@Override
public void persist(State<S, T> state, Message<T> message, Transition<S, T> transition, StateMachine<S, T> stateMachine) {
for (Iterator<PersistentStateChangeListener<S, T>> iterator = getListeners().reverse(); iterator.hasNext();) {
PersistentStateChangeListener<S, T> listener = iterator.next();
listener.persist(state, message, transition, stateMachine);
}
}
}
}
与 spring 中的 recipes 实现相比,我的实现还有另外两个优点。
- 此实现可以与枚举一起使用,而不仅仅是字符串
- 该实现可以与通过计时器触发状态更改的状态机一起使用,因为状态不包含在事件的消息中,而是使用状态机本身的扩展状态。
当然,对于每个事件,都会创建一个新的状态机,但我发现无法确定现有状态机是否仍然处于活动状态(例如异步任务运行、计时器运行)。如果可以找到一种方法来确定这一点,则可以使用状态机池来代替。