What is the ordering of actions performed using spring state machine?
20:17 14 Dec 2025

I have a spring state machine that is tied to states of an object from another service, that is retrieved and updated using HTTP APIs. So, it's not a local database.

I'm thinking to use transition actions to make sure state machine rules are respected, i.e. I need to fetch object from the other service using REST API, call that service REST API to update the object state. If somehow the service is unavailable/return 500, my application's state machine should fail and transition actions shouldn't run.

According to ChatGPT this is the ordering of actions using state machine:

  • interceptor preEvent

  • interceptor preStateChange

  • transition action(s)

  • state exit actions

  • state entry actions

  • interceptor postStateChange

  • listener transition

I'm trying to avoid repeating the definition of transition action calling REST API to update the object state, so I was trying preStateChange. However, in my logs, the preStateChange occurs after the transition action. Here is my code:

@Service
@RequiredArgsConstructor
public class ObjectStateMachineFactory {
  private final StateMachineFactory factory;
  private final UpdateObjectStateInterceptor updateObjectStateInterceptor;

  public StateMachine getStateMachine() {
    StateMachine sm = factory.getStateMachine();

    sm.getStateMachineAccessor()
        .doWithAllRegions(
            access -> access.addStateMachineInterceptor(updateObjectStateInterceptor));

    return sm;
  }
}


@Slf4j
@Service
@RequiredArgsConstructor
public class ObjectStateMachineService {

  private final ObjectStateMachineFactory stateMachineFactory;
  private final ObjectService objectService;
  private final UpdateObjectInterceptor updateObjectInterceptor;

  @Transactional
  public boolean processObjectEvent(String id, ObjectEvent event) {
    CustomObject obj = objectService.getObject(id);
    // TODO: Don't build state machine everytime as its an expensive operation
    StateMachine sm = stateMachineFactory.getStateMachine();
    try {
      sm.startReactively();

      // Set initial state using resetStateMachine
      CustomObjectState currentState =
          CustomObjectState.fromValue(obj.getState().getObj().getKey());

      if (sm.getState() == null || sm.getState().getId() != currentState) {
        sm.getStateMachineAccessor()
            .withRegion()
            .resetStateMachineReactively(
                new DefaultStateMachineContext<>(currentState, null, null, sm.getExtendedState()))

            .block();
      }

      sm.getExtendedState().getVariables().put("customObj", obj);

      boolean success = sm.sendEvent(event);
      }
      return success;
    } finally {
      sm.stop();
    }
  }
}

@Slf4j
@Configuration
@RequiredArgsConstructor
@EnableStateMachineFactory
public class OrderStateConfig extends StateMachineConfigurerAdapter {

  @Override
  public void configure(StateMachineStateConfigurer states)
      throws Exception {
    states
        .withStates()
        .initial(CustomObjectState.UNCONFIRMED)
        .states(EnumSet.allOf(CustomObjectState.class));
  }

  @Override
  public void configure(StateMachineConfigurationConfigurer config)
      throws Exception {

    // IMPORTANT: disable auto-start so interceptor can be attached first
    config.withConfiguration().autoStartup(false);
  }

  @Override
  public void configure(StateMachineTransitionConfigurer transitions)
      throws Exception {
    transitions
        // CONFIRM event
        .withExternal()
        .source(CustomObjectState.A)
        .target(CustomObjectState.B)
        .event(ObjectEvent.CONFIRM)
        .guard(objectStateGuard.canTransitToB())
        .action(sendNotificationAction)
.
.
.

I'm expecting the order:

objectStateGuard.canTransitToB();

UpdateObjectStateInterceptor.preStateChange();

sendNotificationAction

but sendNotificationAction is occuring before preStateChange

is there any way to accomplish this, or am I using the wrong feature of state machine? how to use the state machine without local database? thank you

java spring spring-statemachine