如何处理 spring 状态机未处理的事件
How to handle events that were not processed by spring state machine
假设我们有以下状态机配置:
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
问题是,当我发送一个属于配置但不适用于当前状态的事件时,没有任何反应。
我不知道状态没有改变是因为守卫还是因为当前状态和我的事件没有转换。
有什么办法可以处理这种情况吗?
要记录不适用于您当前状态的事件,您可以使用状态机侦听器。 State Machine中每次传入事件时都会调用一个方法,不满足定义的transitions和events
在您需要覆盖的状态机配置中:
public void configure(StateMachineConfigurationConfigurer<State, Event> config) {
config.withConfiguration()
.listener(customListener());
}
并实现您自己的侦听器 - 最简单的方法是使用 StateMachineListenerAdapter
and override the 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的扩展上下文来记录守卫名称和事件被拒绝的原因。
上下文可用于构造自定义异常或向调用方代码传达发生的情况。
已解决!正如经常发生的那样,解决方案对我来说太简单了:(。所以向 SM 发送事件的方法具有布尔值作为 return 参数。如果事件被处理并处理它 returns为真,否则为假。
就是这样 - 只需检查 return 值!
假设我们有以下状态机配置:
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
问题是,当我发送一个属于配置但不适用于当前状态的事件时,没有任何反应。
我不知道状态没有改变是因为守卫还是因为当前状态和我的事件没有转换。
有什么办法可以处理这种情况吗?
要记录不适用于您当前状态的事件,您可以使用状态机侦听器。 State Machine中每次传入事件时都会调用一个方法,不满足定义的transitions和events
在您需要覆盖的状态机配置中:
public void configure(StateMachineConfigurationConfigurer<State, Event> config) {
config.withConfiguration()
.listener(customListener());
}
并实现您自己的侦听器 - 最简单的方法是使用 StateMachineListenerAdapter
and override the 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的扩展上下文来记录守卫名称和事件被拒绝的原因。 上下文可用于构造自定义异常或向调用方代码传达发生的情况。
已解决!正如经常发生的那样,解决方案对我来说太简单了:(。所以向 SM 发送事件的方法具有布尔值作为 return 参数。如果事件被处理并处理它 returns为真,否则为假。
就是这样 - 只需检查 return 值!