Springが先日リリースした,Statemachineというステートマシンフレームワークのバージョン1.1では,次のような新機能が提供されている。
- Spring Securityのサポート
- @WithStateMachineによるインテグレーション強化
- Redisのビルトインサポート
- UIモデリングのサポート
Webサイトでの説明によれば,Spring Statemachineは,“Springアプリケーションでステートマシンの概念を使用するアプリケーション開発者のためのフレームワーク”である。Statemachineには,SpringのIoC(Inversion of Control)を通じて有限状態機械(FSM, Finite State Machine)にBeanを関連付けるような,通常のSpringフレームワークのコアコンポーネントがすべて含まれている。
FSMのアプリケーションへの展開は,アプリケーションが固定数の状態(ステート)と,状態から状態へと遷移するイベントを持つ場合に有用だ。これらの遷移を発生させるため,ステートマシンは,イベントないしタイマに基づくトリガを使用する。
ステートとイベントは2つのデータ型 - StringとEnumerationを使用して実装することができる。
例えば,次のような状態図を使った回転ドア(turnstile)を実装してみよう。
この回転ドアFSMのステートはLOCKEDとUNLOCKED,イベントはInsertTokenとPassThru,アクションはUnlock,Lock,Alarm,Refundである。初期状態はLOCKEDで,状態図では2重円で示されている。最初のInsertTokenイベントがUnlockアクションをトリガし,LOCKEDからUNLOCKEDへと状態を遷移させる。UNLOCKED状態になると,PassThruイベントの発行がLockアクションをトリガし,回転ドアのステートは再びLOCKEDへと遷移する。AlarmとRefundアクションは状態変化を起こさない。
デモアプリケーションを簡単にするため,アクションの定義は省略する。ステートとイベントは,Enumerationを使って次のように実装できる。
static enum States {
LOCKED,
UNLOCKED
}
static enum Events {
INSERTTOKEN,
PASSTHRU
}
次の作業は,Springの@ConfigurationアノテーションコンテキストをStateMachineConfigureインターフェースに定義して,ステートと遷移を設定することだ。
@Configuration
@EnableStateMachine
static class Config extends EnumStateMachineConfigurerAdapter<States,Events> {
@Override
public void configure(StateMachineStateConfigurer<States,Events> states)
throws Exception {
states
.withStates()
.initial(States.LOCKED)
.states(EnumSet.allOf(States.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<States,Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.LOCKED)
.target(States.UNLOCKED)
.event(Events.InsertToken)
.and()
.withExternal()
.source(States.UNLOCKED)
.target(States.LOCKED)
.event(Events.PassThru);
}
}
@EnableStateMachineはこのコンテキストに対して,回転ドアの構築と開始を指示するためのものだ。
この構成では,LOCKが初期状態であることを,states.withStates().initial(States.LOCKED)というステートメントで定義している。状態遷移は上記に示すように,source(), target(), event()といったメソッドを使って定義する。これら一連のメソッドは,FSM内のすべての状態遷移に対して定義されなくてはならない。状態遷移を実行する標準的な方法がwithExternal()メソッドだ。図中のAlarmやRefundのような状態変化を必要としないアクションには,withInternal()メソッドを使用する。
回転ドアFSMの進行状況を監視するためには,StateMachineListenerを定義する。
static class StateMachineListener extends StateMachineListenerAdapter<States,Events> {
@Override
public void stateChanged(State<States,Events> from,State<States,Events> to) {
System.out.println("State changed to: " + to.getId());
}
}
最後にStateMachineのインスタンスを生成して,リスナのインスタンス生成と回転ドアFSMの開始,イベントの送信を行なうrun()メソッドを定義する。
@Autowired
StateMachine<States,Events> stateMachine;
@Override
public void run(String... args) throws Exception {
StateMachineListener listener = new StateMachineListener();
stateMachine.addStateListener(listener);
stateMachine.start();
stateMachine.sendEvent(Events.InsertToken);
stateMachine.sendEvent(Events.PassThru);
}
public static void main(String[] args) {
SpringApplication.run(org.redlich.statemachine.DemoApplication.class,args);
}
このプロジェクト全体はGitHubで公開している。詳細なリファレンスガイドは,Spring StatemachineのWebサイトで見ることができる。
この記事を評価
- 編集者評
- 編集長対応