State Machine Tutorial

Understand the fundamentals of state machines, including their mathematical foundations and how to use them in Spring Boot.

General TheoryWhat is a State Machine?

A state machine is a computational model that can be in exactly one of a finite number of states at any given time.

  • States: Define the status of the system at a point in time.
  • Events: Trigger transitions between states.
  • Transitions: Define rules for moving from one state to another.
Mathematical ModelFormal Finite State Machine Definition

A state machine can be formally defined as a 5-tuple:

M = (Q, Σ, δ, q₀, F)
  • Q: Set of all states
    Q = {DRAFT, REVIEW, APPROVED, REJECTED}
  • Σ: Set of input events
    Σ = {SUBMIT, APPROVE, REJECT, EDIT}
  • δ: Transition function
    δ(DRAFT, SUBMIT) → REVIEW
    δ(REVIEW, APPROVE) → APPROVED
    δ(REVIEW, REJECT) → REJECTED
    δ(REJECTED, EDIT) → DRAFT
  • q₀: Initial state
    q₀ = DRAFT
  • F: Final states
    F = {APPROVED, REJECTED}
Spring Boot State MachineUsing Spring State Machine Framework
  1. Add spring-statemachine-core as a dependency.
  2. Use enums to define states and events.
  3. Configure transitions using StateMachineConfigurerAdapter.

Java Example:

@Configuration
  @EnableStateMachine
  public class StateMachineConfig extends StateMachineConfigurerAdapter {
  @Override
  public void configure(StateMachineStateConfigurer states) throws Exception {
    states.withStates()
      .initial(State.DRAFT)
      .state(State.REVIEW)
      .end(State.APPROVED)
      .end(State.REJECTED);
  }

  @Override
  public void configure(StateMachineTransitionConfigurer transitions) throws Exception {
    transitions
      .withExternal().source(State.DRAFT).target(State.REVIEW).event(Event.SUBMIT)
      .and()
      .withExternal().source(State.REVIEW).target(State.APPROVED).event(Event.APPROVE)
      .and()
      .withExternal().source(State.REVIEW).target(State.REJECTED).event(Event.REJECT)
      .and()
      .withExternal().source(State.REJECTED).target(State.DRAFT).event(Event.EDIT);
  }
}
Reactive State TransitionsProject Reactor Integration

With Mono:

Mono.just(Event.SUBMIT)
  .doOnNext(event -> stateMachine.sendEvent(event))
  .subscribe();

With Flux:

Flux.just(Event.SUBMIT, Event.APPROVE)
  .delayElements(Duration.ofSeconds(1))
  .doOnNext(event -> stateMachine.sendEvent(event))
  .subscribe();
Advanced TipsGuards, Actions, Listeners
.withExternal()
  .source(State.DRAFT)
  .target(State.REVIEW)
  .event(Event.SUBMIT)
  .guard(ctx -> isValid())
  .action(ctx -> log.info("Transitioned to REVIEW"));