当前位置: 代码迷 >> java >> 连接后的Spring Statemachine内部过渡操作未调用
  详细解决方案

连接后的Spring Statemachine内部过渡操作未调用

热度:54   发布时间:2023-07-25 19:32:38.0

我正在尝试使用forkjoin配置状态机。 加入后,我想使用内部转换对加入状态调用操作。 问题在于,未触发为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();
    }

作为一种解决方法,我添加了几个外部转换(从CD ),但事实是我想通过执行现有操作作为内部转换动作来省略状态D并直接转换到E

我想通过执行现有操作作为内部转换操作来省略状态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情况就是如此)。

  相关解决方案