2016-08-12 1 views
0

PersistHandlerConfig(PersistHachler)を使用してSSMでPOCを実行しています。 これはうまく見えますが、他にもいくつか質問がありました。PersistHandlerConfigのStateMachineFactoryの使用

ユーザごとに1つのインスタンスを持つマルチユーザWebアプリケーションである必要があるため、StateMachineFactoryの推奨に従いコードを変更しようとしましたが、Persistenceのレシピはこのケースを処理する準備ができていません。

PersistHandlerConfig内に(sm idから)必要なstatetemachineを取得する方法はありますか?

@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()); 
    } 

} 

答えて

0

この場合、ウェブアプリケーションと複数のユーザーにとっては少し難解です。 Scopeサンプルでは、​​マシンをセッションスコープBean(ユーザーあたり1台のマシン)として使用し、Eventserviceは、マシンがプールされた(要求ごとに再使用される)リクエストごとに1台のマシンをユーザーに割り当てる方法を示します。

ssmが比較的重いコンポーネントであるため、使用しているユーザーの数によって異なります。そのため、マシンを再利用することはそのような場合には良い考えです。また、ssmがシリアライズ可能でないため、セッションスコープのBeanに問題が発生する可能性があります。 SpringはセッションスコープのBeanをHttpSessionに格納します。つまり、Tomcatはクラスタ化されたサーバーで永続化しようとします。

0

私のマルチユーザ環境でも同じ問題がありました。レシピの概念は実際には機能しません。すべての要求に対してただ1つのステートマシンを使用することは、スレッドセーフではありません。 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); 
     } 
    } 
} 

}

春のレシピの実装に比べて、私の実装では他の二つの利点があります。

  1. この実装は列挙だけでなく文字列
  2. と実装で使用することができる状態は、イベントのメッセージで運ばれていないため、タイマによる状態変化をトリガする状態マシンで使用することができステートマシン自体のextendedStateを使用します。

確かに、イベントごとに新しいステートマシンが作成されますが、既存のステートマシンがまだアクティブな場合(非同期タスクが実行され、タイマーが実行されているなど)は判断できませんでした。これを判断する方法が見つかると、代わりに状態マシンのプールを使用することができます。