0

我们正在使用 PersistHandlerConfig (Persist recipe) 使用 SSM 进行 POC。看起来不错,但出现了一些其他问题。

由于它需要是一个多用户 webapp,每个用户只有一个实例,我们试图遵循 StateMachineFactory 的建议并更改代码,但 Persistence 的配方看起来还没有准备好处理这种情况。

有一种方法可以在 PersistHandlerConfig 中获取所需的 statetemachine(从它的 sm id)?

@Configuration
public class PersistHandlerConfig {

    @Autowired
    private StateMachineFactory<Tasks, Events> statemachinefactory;

    @Bean
    public Persist persist() {
        return new Persist(persistStateMachineHandler());
    }

    // Here is the problem, since this instance should be the one is in use
    // it should be instantiated with the sm id currently activating the persistence
    @Bean
    public PersistStateMachineHandler persistStateMachineHandler() {
        return new PersistStateMachineHandler(statemachinefactory.getStateMachine());
    }

}
4

2 回答 2

1

在这种情况下,对于 webapp 和多个用户来说,事情变得有点棘手。Scope示例展示了如何将机器用作会话范围的 bean(每个用户一台机器),并Eventservice展示了如何在机器被池化的情况下每个请求使用一台机器(每个请求重用)。

这取决于您拥有多少用户,因为 ssm 是相对较重的组件,因此在这些情况下重用机器是个好主意。此外,由于 ssm 不可序列化,您可能会遇到会话范围 bean 的问题。Spring 将会话范围的 bean 存储在HttpSession其中,即 tomcat 可能会尝试为集群服务器持久化。

于 2016-08-13T05:34:20.257 回答
0

我的多用户环境也有同样的问题。食谱的概念并没有真正起作用。对所有请求仅使用一个状态机不是线程安全的。我以 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 实现相比,我的实现还有另外两个优点。

  1. 此实现可以与枚举一起使用,而不仅仅是字符串
  2. 该实现可以与通过计时器触发状态更改的状态机一起使用,因为状态不包含在事件的消息中,而是使用状态机本身的扩展状态。

当然,对于每个事件,都会创建一个新的状态机,但我发现无法确定现有状态机是否仍然处于活动状态(例如异步任务运行、计时器运行)。如果可以找到一种方法来确定这一点,则可以使用状态机池来代替。

于 2017-03-17T15:50:56.477 回答