21. 监听状态机事件

有一些用例只是想知道状态机发生了什么,对某些事情做出反应或仅仅为了调试目的而进行日志记录。 SSM提供了用于添加监听器的接口,然后在出现各种状态更改,动作等时提供选项以获得回调。

你基本上有两个选择,要么监听Spring应用程序上下文事件,要么直接将监听器附加到状态机。 这些基本上都会提供相同的信息,其中一个通过监听器接口将事件生成为事件类和其他生成回调。 这两者都有优点和缺点,将在稍后讨论。

21.1 应用程序上下文事件

应用程序上下文事件类包括OnTransitionStartEvent,OnTransitionEvent,OnTransitionEndEvent,OnStateExitEvent,OnStateEntryEvent,OnStateChangedEvent,OnStateMachineStart和OnStateMachineStop等扩展基本事件类StateMachineEvent的类。这些类可以像Spring类型的ApplicationListener一样使用。

StateMachine将通过设置的StateMachineEventPublisher发送上下文事件。 如果@Configuration类使用@EnableStateMachine注释,则会自动创建默认实现。

public class StateMachineApplicationEventListener
        implements ApplicationListener<StateMachineEvent> {

    @Override
    public void onApplicationEvent(StateMachineEvent event) {
    }
}

@Configuration
public class ListenerConfig {

    @Bean
    public StateMachineApplicationEventListener contextListener() {
        return new StateMachineApplicationEventListener();
    }
}

上下文事件也通过@EnableStateMachine自动启用,状态机机构建器(builder)StateMachine注册为bean,如下所示。

@Configuration
@EnableStateMachine
public class ManualBuilderConfig {

    @Bean
    public StateMachine<String, String> stateMachine() throws Exception {

        Builder<String, String> builder = StateMachineBuilder.builder();
        builder.configureStates()
            .withStates()
                .initial("S1")
                .state("S2");
        builder.configureTransitions()
            .withExternal()
                .source("S1")
                .target("S2")
                .event("E1");
        return builder.build();
    }
}

21.2 状态机监听器

使用StateMachineListener,可以扩展它并实现所有回调方法,也可以使用包含存根方法实现的StateMachineListenerAdapter类,并选择要覆盖哪些方法。

public class StateMachineEventListener
        extends StateMachineListenerAdapter<States, Events> {

    @Override
    public void stateChanged(State<States, Events> from, State<States, Events> to) {
    }

    @Override
    public void stateEntered(State<States, Events> state) {
    }

    @Override
    public void stateExited(State<States, Events> state) {
    }

    @Override
    public void transition(Transition<States, Events> transition) {
    }

    @Override
    public void transitionStarted(Transition<States, Events> transition) {
    }

    @Override
    public void transitionEnded(Transition<States, Events> transition) {
    }

    @Override
    public void stateMachineStarted(StateMachine<States, Events> stateMachine) {
    }

    @Override
    public void stateMachineStopped(StateMachine<States, Events> stateMachine) {
    }

    @Override
    public void eventNotAccepted(Message<Events> event) {
    }

    @Override
    public void extendedStateChanged(Object key, Object value) {
    }

    @Override
    public void stateMachineError(StateMachine<States, Events> stateMachine, Exception exception) {
    }

    @Override
    public void stateContext(StateContext<States, Events> stateContext) {
    }
}

在上面的例子中,我们简单地创建了我们自己的监听器类StateMachineEventListener,它扩展了StateMachineListenerAdapter。

Listener方法stateContext提供对不同阶段的各种StateContext更改的访问。 更多关于它的章节,第19章,使用StateContext。

一旦你定义了你自己的监听器,它可以通过它的接口注册到状态机中,如下所示。 这只是一个味道问题,如果它被连接在弹簧配置中或在任何应用程序生命周期中手动完成。

public class Config7 {

    @Autowired
    StateMachine<States, Events> stateMachine;

    @Bean
    public StateMachineEventListener stateMachineEventListener() {
        StateMachineEventListener listener = new StateMachineEventListener();
        stateMachine.addStateListener(listener);
        return listener;
    }

}

21.3 限制和问题

Spring应用程序上下文并不是最快的事件总线,因此建议您考虑一下事件状态机正在发送的事件的速率。 为了获得更好的性能,最好使用StateMachineListener接口。 由于这个特定的原因,可以在@EnableStateMachine和@EnableStateMachineFactory中使用contextEvents标志来禁用Spring应用程序上下文事件,如上所示。

@Configuration
@EnableStateMachine(contextEvents = false)
public class Config8
        extends EnumStateMachineConfigurerAdapter<States, Events> {
}

@Configuration
@EnableStateMachineFactory(contextEvents = false)
public class Config9
        extends EnumStateMachineConfigurerAdapter<States, Events> {
}

results matching ""

    No results matching ""