Context
I recently came across Spring State Machine while working on a project that uses Spring Boot. At first glance, it seemed like a perfect fit.
However, I quickly ran into a few challenges:
-
Managing custom exceptions felt awkward and required hacks.
-
I needed to instantiate multiple state machines through a pool (since maintaining them per session or thread is discouraged).
-
A Spring State Machine only processes one event at a time, which I found limiting—even though state transitions are fast.
-
Overall, the framework feels unnecessarily stateful, and I don’t see why it has to be that way.
That said, the documentation is very clear and helped me learn a lot about state machine concepts.
Discussion
While digging into the source code, I noticed a fundamental issue: Spring State Machine tightly couples transitions with the current state. From my perspective, transitions should be static and immutable, while the current state can change independently.
If transitions are immutable, they can safely be shared across threads without synchronization concerns.
Based on this idea, I implemented a simpler solution—what I now call a state manager. Transitions are stored in a Map
-like structure, where the key is [sourceState, event]
and the value is the targetState
.
This means you only need to perform a simple lookup with the current state and the incoming event. Guards and actions can then be layered on top of this lookup logic.
The result is:
-
No synchronization needed.
-
A single state manager instance can be reused across threads or created on the fly.
-
Works very well for simple state machines.
Of course, it doesn’t yet cover more complex scenarios like regions or nested states—higher abstractions may be needed for that. But as a starting point, this approach has been effective.
Conclusion
State machines are a powerful tool and appear often in business requirements. But I believe they should be isolated from business code rather than embedded directly. Unfortunately, I haven’t yet found a simple, production-friendly implementation in Java.
In my next post, I’ll share a more advanced version of this state manager, which I’ve used successfully to extend an existing approval system. The code is on GitHub (still a work in progress).
My takeaway: a lightweight state manager as an internal service class often provides more flexibility than a fully-fledged state machine framework. It leverages existing application infrastructure for persistence, business rules, and object scope—without unnecessary complexity.
Thanks for reading, and I look forward to your comments.
🔗 Related post: Why developers never use state machines