问题描述
我正在尝试使用fork
和join
配置状态机。
加入后,我想使用内部转换对加入状态调用操作。
问题在于,未触发为withInternal()
配置的操作。
我已经尝试过.guard(context -> true)
hack,并且我也玩过.timer()
和.timerOnce()
,但是它也不起作用。
这是状态配置:
private void configureStates(StateMachineBuilder.Builder<String, String> builder) throws Exception {
builder.configureStates()
.withStates()
.initial("A")
.fork("B")
.join("C")
.state("A")
.state("B_")
.state("C")
.state("D")
.state("E")
.and()
.withStates()
.parent("B_")
.initial("B1")
.end("C1")
.and()
.withStates()
.parent("B_")
.initial("B2")
.end("C2")
.and()
.withStates()
.parent("B_")
.initial("B3")
.end("C3")
.end("E");
}
过渡配置:
private void configureTransitions(StateMachineBuilder.Builder<String, String> builder) throws Exception {
builder.configureTransitions()
.withExternal()
.source("A")
.target("B")
.event("E0")
.action(context -> log.info("From A to B"))
.and()
.withInternal()
.source("B")
.guard(stateContext -> true)
.action(context -> log.info("At B"))
.timerOnce(50)
.and()
.withFork()
.source("B")
.target("B_")
.and()
.withExternal()
.source("B1")
.target("C1")
.event("E1")
.and()
.withExternal()
.source("B2")
.target("C2")
.event("E2")
.and()
.withExternal()
.source("B3")
.target("C3")
.and()
.withExternal()
.source("C3")
.target("A")
.event("E3")
.and()
.withJoin()
.source("B_")
.target("C")
.and()
.withInternal()
.source("C")
.guard(context -> true)
.action(context -> log.info("At C"))
.timerOnce(50)
.state("C")
.and()
.withExternal()
.source("C")
.target("D")
.action(context -> log.info("At D"))
.and()
.withInternal()
.source("D")
.guard(stateContext -> true)
.action(stateContext -> log.info("At internal D"))
.timer(10)
.and()
.withExternal()
.source("D")
.event("E4")
.target("E");
}
我还向状态机添加了一个侦听器:
private StateMachineListener<String, String> listener() {
return new StateMachineListenerAdapter<String, String>() {
@Override
public void stateChanged(State<String, String> from, State<String, String> to) {
log.info("State transited from [{}] to [{}]",
from == null ? null : from.getId(),
to == null ? null : to.getId());
}
};
}
最终配置为:
private StateMachine<String, String> buildMachine() throws Exception {
StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureConfiguration()
.withConfiguration()
.listener(listener())
.autoStartup(true);
configureStates(builder);
configureTransitions(builder);
return builder.build();
}
问题在于没有内部转换动作被调用。
我为给定的配置创建了一个小测试:
@Test
public void testForkJoin() throws Exception {
StateMachine<String, String> machine = buildMachine();
StateMachineTestPlan<String, String> plan = StateMachineTestPlanBuilder.<String, String>builder()
.defaultAwaitTime(3)
.stateMachine(machine)
.step()
.expectStates("A")
.and()
.step()
.sendEvent("E0")
.expectStates("B_", "B1", "B2", "C3")
.and()
.step()
.sendEvent("E1")
.expectStates("B_", "C1", "B2", "C3")
.and()
.step()
.sendEvent("E3")
.expectState("A")
.and()
.step()
.sendEvent("E0")
.expectStates("B_", "B1", "B2", "C3")
.and()
.step()
.sendEvent("E1")
.expectStates("B_", "C1", "B2", "C3")
.and()
.step()
.sendEvent("E2")
.expectStates("D")
.and()
.step()
.sendEvent("E4")
.expectState("E")
.and()
.build();
plan.test();
}
作为一种解决方法,我添加了几个外部转换(从C
到D
),但事实是我想通过执行现有操作作为内部转换动作来省略状态D
并直接转换到E
1楼
我想通过执行现有操作作为内部转换操作来省略状态D并直接转换为E。
简短的回答:不能。
Fork / Join伪状态不应引入行为规范(例如Action)。 Fork / Join仅用于在SM(临时伪状态)中对并行操作(fork)和同步(join)进行建模。
Spring State Machine实现遵循 ,因此不会执行与fork / join相关的动作。
动作与特定的过渡或状态相关联。
与转换相关的动作:
执行JOIN时,您可能有N(> = 2)个源(J1E,J2E-该其他区域的最后阶段),因此从J1E过渡到JOIN阶段(action = A1)以及从J2E过渡到JO2阶段时,可以定义不同的动作。 JOIN阶段(动作= A2)。
与状态相关的动作:
如果您有一个需要在并行操作同步后执行的通用操作,则可以将其定义为下一个转换的一部分(例如,我相信从C转换为D时,您的SM情况就是如此)。