如何处理弹簧状态机未处理的事件

时间:2018-12-26 15:33:44

标签: java spring spring-statemachine

假设我们具有以下状态机配置:

transitions.withExternal()
    .source(FIRST)
    .target(SECOND)
    .event(STEP_EVENT)

    .and()

    .source(SECOND)
    .target(EXIT)
    .event(EXIT_EVENT)

事件列表:STEP_EVENT,EXIT_EVENT,UNUSED_EVENT

stateMachine.init(); 
// FIRST state

stateMachine.sendEvent(STEP_EVENT); 
/* state moves to SECOND 
because there is a transition with current state as a source 
and STEP_EVENT as transition event */

stateMachine.sendEvent(UNUSED_EVENT); 
/* no state change. 
This will trigger "eventNotAccepted(Message<Events> event)" 
in state machine listener, 
because UNUSED_EVENT is never mentioned in SM config */

stateMachine.sendEvent(STEP_EVENT); 
/* nothing will happen!!! 
No state change, as there is no transition 
which has current state (SECOND) as source 
and STEP_EVENT as transition event, 
and no eventNotAccepted call. 
But I need it, I want to fail here! */

stateMachine.sendEvent(EXIT_EVENT); 
// state will move to EXIT

问题是,当我发送事件(该事件是配置的一部分,但不适用于当前状态)时,什么也没发生。

我不知道状态是否由于警卫而改变,或者因为当前状态和事件没有过渡。

有什么办法可以处理这种情况?

2 个答案:

答案 0 :(得分:0)

要记录不适用于您当前状态的事件,可以使用StateMachine侦听器。每次在状态机中传递事件时都会调用一种方法,该方法不满足定义的转换和事件。

在状态机配置中,您需要覆盖:

public void configure(StateMachineConfigurationConfigurer<State, Event> config) {
  config.withConfiguration()
     .listener(customListener());
}

并实现自己的侦听器-最简单的方法是使用StateMachineListenerAdapter并覆盖eventNotAccepted(Message event)方法:

private StateMachineListenerAdapter<State, Event> customListener() {
  return new StateMachineEventListenerAdapter<State, Event>() {

    @Override
    public void eventNotAccepted(Message event) {
      //LOG which event was not accepted etc.
    }
  }
}

要记录警卫的结果-在警卫本身中使用日志消息。

如果要在警卫之外公开原因,则可以构造一个键值对,并使用StateMachine的扩展上下文记录警卫名称以及拒绝事件的原因。 上下文可用于构造自定义异常或将发生的情况传达给调用者代码。

答案 1 :(得分:0)

解决了!通常,解决方案对我来说太简单了:(。因此,将事件发送给SM的方法将布尔值作为返回参数。如果事件被处理,则返回true,否则返回false。

就这样-只需检查返回值即可!