20. Triggering Transitions
驱动状态机是通过由触发器触发的转换完成的。 目前支持的触发器是EventTrigger和TimerTrigger。
20.1 EventTrigger
EventTrigger是最有用的触发器,因为它允许用户通过向它发送事件直接与状态机进行交互。 这些事件也被称为信号。 只需通过在配置期间将状态与其关联即可将触发器添加到转换中。
@Autowired
StateMachine<States, Events> stateMachine;
void signalMachine() {
stateMachine.sendEvent(Events.E1);
Message<Events> message = MessageBuilder
.withPayload(Events.E2)
.setHeader("foo", "bar")
.build();
stateMachine.sendEvent(message);
}
在上面的例子中,我们使用两种不同的方式发送事件。 首先,我们使用状态机API方法sendEvent(E事件)发送一个类型安全的事件。 其次,我们使用api方法sendEvent(Message <E> message)发送包含在Spring消息消息中的事件和自定义事件头。 这允许用户通过事件添加任意额外的信息,当用户正在执行操作时,该事件对StateContext可见。
通常会传递消息标题,直到机器运行完成以执行特定事件。 例如,如果一个事件正在转换到一个状态为A的匿名状态转换为状态B,那么原始事件可用于状态B中的操作或警卫。
20.2 TimerTrigger
当需要在没有任何用户交互的情况下自动触发某些事件时,TimerTrigger非常有用。 通过在配置期间将定时器与定时器相关联,触发器被添加到转换中。
目前支持两种类型的定时器,一种是连续触发的,另一种是一旦输入源状态就触发。
@Configuration
@EnableStateMachine
public class Config2 extends StateMachineConfigurerAdapter<String, String> {
@Override
public void configure(StateMachineStateConfigurer<String, String> states)
throws Exception {
states
.withStates()
.initial("S1")
.state("S2")
.state("S3");
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions)
throws Exception {
transitions
.withExternal()
.source("S1").target("S2").event("E1")
.and()
.withExternal()
.source("S1").target("S3").event("E2")
.and()
.withInternal()
.source("S2")
.action(timerAction())
.timer(1000)
.and()
.withInternal()
.source("S3")
.action(timerAction())
.timerOnce(1000);
}
@Bean
public TimerAction timerAction() {
return new TimerAction();
}
}
public class TimerAction implements Action<String, String> {
@Override
public void execute(StateContext<String, String> context) {
// do something in every 1 sec
}
}
在上面我们有三个状态,S1,S2和S3。 我们有一个正常的外部转换,从S1到S2,从S1到S3分别有事件E1和E2。 有趣的部分是当我们为源状态S2和S3定义内部转换时。
对于这两个转换,我们将Action bean timerAction关联到源状态S2将使用计时器并且S3将使用timerOnce。 给出的值是毫秒,在这些情况下意味着1000毫秒。
一旦状态机接收到事件E1,就执行从S1到S2的转换并启动定时器。只要状态保持在S2中,TimerTrigger执行并导致与该状态相关的转换,在这种情况下,该转换是具有timerAction的内部转换定义。
一旦状态机接收到事件E2,就从S1转换到S3,并且定时器启动。在定时器定义的延迟之后进入状态后,该定时器只执行一次。
幕后计时器是一个简单的触发器,可能会导致转换发生。 使用定时器()定义转换将保持触发触发器,并且只有在源状态处于活动状态时才会导致转换。 使用timerOnce()进行转换有点不同,因为它只会在实际输入源状态后的延迟之后触发。
使用timerOnce()如果你想要在延迟之后发生某些事情,那么只要进入状态一次。