Spring状态机访问bean时执行动作导致状态机终止

问题描述

我正在尝试创建一个状态机,该状态机将经历一系列状态,从而对某些状态加上状态转换拦截器触发进入动作。

要测试此状态机,我创建了一个Spring Boot集成测试,该测试向集成通道提供一条消息,该通道进而调用此状态机。我注意到的是,当这些动作发生时,当它开始与“ repository” bean进行交互时,它将导致状态机退出并且集成测试失败。我没有在日志中看到任何错误,但是当我引入“错误”操作时,状态机操作的行为符合预期。

我尝试将断点应用于拦截器,但是我注意到的是,由于断点而导致测试暂停时,到达repository.save(entity)行后,它将允许测试向前走,就好像我在断点处击打,但调试器本身处于动作状态。

当我引入errorAction()时,状态机的行为就会适当。我真的不知道为什么错误操作会导致机器正常完成。

配置如下

@Configuration
@EnableStateMachineFactory
public class NotificationStateMachineConfiguration
    extends StateMachineConfigurerAdapter<NotificationState,NotificationEvent> {
  private static final Logger LOGGER =
      LoggerFactory.getLogger(NotificationStateMachineConfiguration.class);

  @Autowired
  private SendingAction sendingAction;
  @Autowired
  private TransformationAction transformationAction;

  @Override
  public void configure(
      StateMachineConfigurationConfigurer<NotificationState,NotificationEvent> config)
      throws Exception {
    config.withConfiguration()
        .autoStartup(false)
        .taskExecutor(new SyncTaskExecutor())
        .listener(new StateMachineListenerAdapter<NotificationState,NotificationEvent>() {
          @Override
          public void stateChanged(State<NotificationState,NotificationEvent> from,State<NotificationState,NotificationEvent> to) {
            LOGGER.trace("StateChanged - From: {},To: {}",from,to);

          }
        });
  }

  @Override
  public void configure(
      StateMachinestateConfigurer<NotificationState,NotificationEvent> states) throws Exception {
    states.withStates()
        .initial(NotificationState.NEW)
        .state(NotificationState.NEW)
        .state(NotificationState.TRANSFORMING,transformationAction,errorAction())
        .state(NotificationState.TRANSFORMATION_Failed)
        .state(NotificationState.SENDING,sendingAction,errorAction())
        .state(NotificationState.STAGED)
        .state(NotificationState.AWAITING)
        .end(NotificationState.NOT_SENT)
        .end(NotificationState.RESPONSE_RECEIVED)
        .end(NotificationState.ERRORS)
        .end(NotificationState.NEGATIVE_RESPONCE_RECIEVED)
        .end(NotificationState.SENT);
  }

  @Override
  public void configure(
      StateMachineTransitionConfigurer<NotificationState,NotificationEvent> transitions)
      throws Exception {
    transitions
        .withExternal()
        .source(NotificationState.NEW).target(NotificationState.TRANSFORMING)
        .event(NotificationEvent.TRANSFORMATION_REQUESTED)
        .and()
        .withExternal()
        .source(NotificationState.TRANSFORMING).target(NotificationState.SENDING)
        .event(NotificationEvent.TRANSFORMATION_SUCCESSFULL)
        .and()
        .withExternal()
        .source(NotificationState.TRANSFORMING).target(NotificationState.TRANSFORMATION_Failed)
        .event(NotificationEvent.TRANSFORMATION_FAILURE)
        .and()
        .withExternal()
        .source(NotificationState.SENDING).target(NotificationState.AWIATING)
        .event(NotificationEvent.PROOF_OF_DELIVERY_RELEASE_REQUESTED)
        .and()
        .withExternal()
        .source(NotificationState.SENDING).target(NotificationState.SENT)
        .event(NotificationEvent.RELEASE_REQUESTED)
        .and()
        .withExternal()
        .source(NotificationState.SENDING).target(NotificationState.STAGED)
        .event(NotificationEvent.STAGE_NOTIFICATION_REQUESTED);
  }


<!-- if i remove this bean the state machine dies within the interceptor when i try to utilize the repository -->
  @Bean
  public Action<NotificationState,NotificationEvent> errorAction() {
    return context -> {
      // RuntimeException("MyError") added to context
      Exception exception = context.getException();
      LOGGER.error(Optional.ofNullable(exception).map(Exception::getMessage)
          .orElse("NO ERROR"));
    };
  }


}

拦截



@Component
public class NotificationStateInterceptor extends
    StateMachineInterceptorAdapter<NotificationState,NotificationEvent> {

  private static final Logger logger =
      LoggerFactory.getLogger(NotificationStateInterceptor.class.getName());
  private final NotificationRepository  repository ;

  public NotificationStateInterceptor(NotificationRepository repository) {
    this.repository = eventProducrepositoryer;
  }

  /**
   * Persist the notification that just changed state.
   *
   * @param state        the notification has just changed to.
   * @param message      that triggered the state change.
   * @param transition   that was triggered during the stage change.
   * @param stateMachine that is managing the notification's state.
   */
  @Override
  public void postStateChange(
      State<NotificationState,NotificationEvent> state,Message<NotificationEvent> message,Transition<NotificationState,NotificationEvent> transition,StateMachine<NotificationState,NotificationEvent> stateMachine) {

    /* trigger the more descriptive version */
    this.postStateChange(state,message,transition,stateMachine,null);
  }


  /**
   * Persist the notification that just changed state.
   *
   * @param state            the notification has just changed to.
   * @param message          that triggered the state change.
   * @param transition       that was triggered during the stage change.
   * @param stateMachine     that is managing the notification's state.
   * @param rootStateMachine in the event that this is a nested state machine.
   */
  @Override
  public void postStateChange(
      State<NotificationState,NotificationEvent> stateMachine,NotificationEvent> rootStateMachine) {

    Notification notification = getNotification(stateMachine);
    if (transition.getKind() != TransitionKind.INITIAL) {
      if (notification != null) {
        logger.debug(
            "Transitioning Notification: " + notification.getId()
                + " to State: " + state.getId());
        notification.applyNewState(state.getId());
          repository.save(notification); 
      }
    }

  }


}

我不确定提供errorAction()bean时是什么导致机器正确完成,而没有提供它时,应用程序也无法正确完成。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)