What is Spring Statemachine, and what are the core building blocks of a state machine (states, transitions, events)?
answer
- States + events + transitions = FSM
- StateMachine<S,E>, S/E usually enums
- Guards veto, actions do side effects
- sendEvent reactive Mono<Message>
- Extended state = data, not new states
basics
~20 sSpring Statemachine is a framework for modelling finite state machines. A machine has states (where it currently sits), events (inputs you send), and transitions (rules that move it from one state to another when an event fires).
solid answer
~40 sSpring Statemachine (spring-statemachine-core) lets you model application logic as an explicit finite state machine instead of scattered boolean flags and if/else. The core abstractions are: states (the discrete modes the machine can be in, with one initial state and optionally end states), events (the inputs/triggers you send), and transitions (source state -> target state, fired by an event, optionally protected by a guard and running an action). The runtime object is StateMachine<S, E>, parameterised by your state and event types — usually enums. You drive it by calling sendEvent(...); it evaluates whether a transition for the current state accepts that event, and if so moves to the target. It also supports guards, actions, listeners, hierarchical (nested) states, orthogonal regions, and extended state variables for data that shouldn't explode the state count.
code
java · 9 linespublic enum OrderState { NEW, PAID, SHIPPED, DELIVERED, CANCELLED }
public enum OrderEvent { PAY, SHIP, DELIVER, CANCEL }
// Driving a machine (reactive API):
stateMachine.startReactively().block();
stateMachine
.sendEvent(Mono.just(MessageBuilder.withPayload(OrderEvent.PAY).build()))
.blockLast(); // Flux<StateMachineEventResult>
// current state now PAID if a NEW --PAY--> PAID transition exists and its guard passedgo deeper
Must be able to name the three pillars: states, events, transitions, and that it models a finite state machine.
Should add the StateMachine<S,E> type, enums for S/E, and the reactive sendEvent + extended state.
Should discuss external/internal/local transitions and when a state machine beats boolean flags.
Frames it as making lifecycle a first-class, enforceable spec; weighs it against simpler alternatives and downstream persistence/concurrency concerns.
## What it is Spring Statemachine is a Spring project (artifact `spring-statemachine-core`) for building **finite state machines (FSMs)** — and beyond, statecharts with nesting and parallelism. A finite state machine is a model where a system is always in exactly one of a finite set of **states**, and moves between them only via defined **transitions** triggered by **events**. The value is making implicit control flow (order status, checkout wizard, connection lifecycle, document approval) *explicit, centralised, and enforceable*, instead of a tangle of boolean flags and scattered `if` checks. ## The core vocabulary - **State** — a discrete mode the machine can occupy, e.g. `NEW`, `PAID`, `SHIPPED`. Exactly one **initial state** is mandatory (the machine starts there when started). States may be marked **end/final** states. States can have **entry**, **exit**, and **do** actions. - **Event** — an input/trigger you send into the machine, e.g. `PAY`, `SHIP`. Events are what *cause* transitions to be evaluated. - **Transition** — a rule: *from source state, on event E, go to target state*. It may carry a **guard** (a boolean precondition that can veto it) and one or more **actions** (side effects run during the transition). Transitions come in three flavours: **external** (default — exits source, enters target, runs entry/exit actions), **internal** (source == target, no exit/entry, used to run an action without leaving the state), and **local** (for hierarchical states — moves between parent and child without exiting/re-entering the shared parent). - **StateMachine<S, E>** — the runtime object, generically typed on your state type `S` and event type `E`. In practice `S` and `E` are almost always **enums**. ## How you use it You typically define types as enums and configure the machine with a `StateMachineConfigurerAdapter`. Then you obtain a `StateMachine<S,E>` (via `@EnableStateMachine` for a single shared instance, or `@EnableStateMachineFactory` to create per-request instances), `start()` it, and feed it events. Sending an event asks: *does the current state have a transition accepting this event whose guard passes?* If yes, actions run and the state advances; if no, the event is dropped (accepted == false). ### Sending events — modern vs legacy API Older code calls the **deprecated** blocking `stateMachine.sendEvent(E event)` returning a `boolean`. Current Spring Statemachine (2.x+) exposes a **reactive** API: `sendEvent(Mono<Message<E>> event)` returning a `Flux<StateMachineEventResult<S,E>>`. You wrap the event in a Spring `Message` (`MessageBuilder.withPayload(event).build()`), which also lets you attach **headers** that guards/actions can read via the `StateContext`. ## Extended state — the escape hatch Not everything should be a state. If you tracked "3 retries left" as states you'd get a combinatorial explosion. Instead the machine carries an **extended state** — a `Map` of variables (`stateMachine.getExtendedState().getVariables()`) that actions/guards read and write. Rule of thumb: use *states* for qualitatively different modes, *extended state variables* for quantitative/data details. ## When to use it Reach for it when the domain has a **genuine lifecycle** with rules about which transitions are legal (order processing, approvals, device/connection lifecycle, multi-step wizards). It shines when illegal transitions must be *prevented*, when the diagram is a real spec, and when behaviour on entry/exit matters. Skip it for trivial two-state toggles — a boolean is cheaper. ## Common gotchas - Forgetting to `start()` the machine (it does nothing until started; auto-start is configurable). - Assuming a rejected event throws — it does not; it just isn't accepted. - Treating the default `@EnableStateMachine` bean as thread-safe per user — it is a **single shared instance**; use a factory for concurrency.
- What happens if you send an event the current state has no transition for?Nothing state-changing: the event is simply not accepted. The reactive API reports resultType DENIED in the StateMachineEventResult; the deprecated boolean API returns false. It does not throw by default.
- When would you use an extended state variable instead of adding a state?For quantitative or data-carrying details (retry counts, an amount, a user id) that would otherwise multiply the number of states. States model qualitative modes; extended state holds data guards and actions consult.
saying these in an interview costs you the question
- Thinking an unhandled event throws an exception
- Believing the default @EnableStateMachine bean is per-user/thread-safe
- Modelling every data value as its own state, causing state explosion
- Confusing events (inputs) with states (modes)