惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
T
Tenable Blog
Webroot Blog
Webroot Blog
L
Lohrmann on Cybersecurity
S
Securelist
S
Schneier on Security
NISL@THU
NISL@THU
Know Your Adversary
Know Your Adversary
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
C
CXSECURITY Database RSS Feed - CXSecurity.com
O
OpenAI News
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
S
Secure Thoughts
Application and Cybersecurity Blog
Application and Cybersecurity Blog
P
Privacy International News Feed
H
Hacker News: Front Page
N
Netflix TechBlog - Medium
M
MIT News - Artificial intelligence
博客园 - Franky
PCI Perspectives
PCI Perspectives
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Azure Blog
Microsoft Azure Blog
MongoDB | Blog
MongoDB | Blog
L
LangChain Blog
P
Proofpoint News Feed
S
Security Affairs
WordPress大学
WordPress大学
The Last Watchdog
The Last Watchdog
S
SegmentFault 最新的问题
小众软件
小众软件
F
Full Disclosure
博客园 - 叶小钗
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
The Blog of Author Tim Ferriss
Simon Willison's Weblog
Simon Willison's Weblog
P
Palo Alto Networks Blog
Security Latest
Security Latest
P
Proofpoint News Feed
月光博客
月光博客
T
Tailwind CSS Blog
Scott Helme
Scott Helme
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
T
Threat Research - Cisco Blogs
Help Net Security
Help Net Security
Project Zero
Project Zero

磊磊落落

世間有大愛,世間有大我 - 磊磊落落 端午遊遼寧團山海洋公園 - 磊磊落落 為什麼要讀古文? - 磊磊落落 莊河老街 - 磊磊落落 春遊橫山寺 - 磊磊落落 莊河青堆子古鎮 - 磊磊落落 在日常生活中,可以用 OpenClaw 做哪些事? - 磊磊落落 如何在 CentOS Stream 9 上安装 OpenClaw,并接入企业微信? 当下人人都在养龙虾,这龙虾(OpenClaw)为啥突然就火了? - 磊磊落落 编写一个 VS Code 扩展:将 Copilot 支持的大模型通过 REST API 方式暴露出来 编写提示词需要遵循的五个原则(附实践案例) - 磊磊落落 關於 2026 年即將生效的「吸毒記錄可封存」法案 - 磊磊落落 如何使用 Spec Kit 工具进行规范驱动开发? - 磊磊落落 Markdown 将成为 AI 时代的通用编程语言? - 磊磊落落 使用 FastMCP 编写一个 MySQL MCP Server Cursor 初体验:将 React 项目从 JavaScript 升级到 TypeScript 以自然语言的方式使用 Playwright MCP 进行浏览器自动化操作 - 磊磊落落 MCP 是什么?它是如何工作的? - 磊磊落落 2025 國慶假期總結 - 磊磊落落 週末逛泊霞灣與橫山寺 - 磊磊落落 如何在 Spring Boot 中使用 P6Spy 拦截 SQL 语句? Java 中如何使用 MapStruct 进行对象映射? - 磊磊落落
如何将 Spring Statemachine 作为一个轻量级工作流引擎来使用? - 磊磊落落
磊磊落落 · 2026-03-08 · via 磊磊落落

本文将探讨 Spring Statemachine 作为一个轻量级工作流引擎使用的可行性。文章首先介绍 State Machine 的基本概念,然后讲解 Spring Statemachine 的核心特性,最后通过电商订单状态流转的实战案例,演示将 Spring Statemachine 作为工作流引擎的具体应用。

1 State Machine 是什么?

State Machine(状态机)是一个用来描述事物在不同状态之间如何转换的数学模型。其包含三个核心要素:状态(State)、事件(Event)、转换(Transition)。

  • 状态(State)

状态是指事物可能处于的某种情形或阶段。比如:一个订单处于已创建(CREATED)或已支付状态(PAID)。

  • 事件(Event)

事件是指引发状态发生变化的外部动作或内部触发。比如:对一个订单进行支付(PAY)或运输(SHIP)操作。

  • 转换(Transition)

转换是指从一个状态到另一个状态的变化规则。比如:一个订单从已支付(PAID)状态,经过运输(SHIP)事件,转移到已运输(SHIPPED)状态。

一个完整的电商订单状态的流转过程如下:

[DRAFT] -- CREATE 事件 --> [CREATED] -- PAY 事件 --> [PAID] -- SHIP 事件 --> [SHIPPED] -- DELIVER 事件 --> [DELIVERED]

2 Spring Statemachine 是什么?

Spring Statemachine 是 Spring 生态中的一个专门用来构建和管理 State Machine 的框架。它把上面提到的 State Machine 概念,变成了 Java 开发者可以直接使用的工具。

我们可以把它理解成一个「状态机工厂」—— 只需要告诉它业务规则(有哪些状态、什么事件触发什么变化),它就会帮我们自动管理整个状态的流转过程。

没有 Spring Statemachine 时,我们需要自己编写大量的 if-else 代码来判断状态并执行对应的业务逻辑:

如果订单状态是 CREATED,并且用户进行了 PAY 操作
  则调用支付接口
  并把状态改成 PAID
  ...

否则,如果订单状态是 PAID,并且后台管理员进行了 SHIP 操作
  则调用物流接口
  并把状态改成 SHIPPED
  ...

这种代码写多了就会变成难以维护的「面条代码」。

而有了 Spring Statemachine 后,我们只需要定义规则,框架会负责执行规则里的逻辑:

规则 1:CREATED → PAY 事件 → PAID
规则 2:PAID → SHIP 事件 → SHIPPED
规则 3:SHIPPED → DELIVER 事件 → DELIVERED

定义好规则后,我们只需要告诉它:「触发支付事件」,框架就会自动触发预先绑定的业务逻辑。带来的好处是将状态管理代码和具体业务代码进行了解耦,职责明确,易于维护。

Spring Statemachine 的主要组成部分:

  • 状态定义器

列出所有可能的状态。比如订单的状态:DRAFT、CREATED、PAID、SHIPPED、DELIVERED。

  • 事件定义器

定义所有可能触发的动作。比如订单的事件:CREATE、PAY、SHIP、DELIVER。

  • 转换配置器

连接状态和事件,形成规则。比如转换规则:CREATED 状态遇到 PAY 事件后变成 PAID 状态。

  • 动作执行器

在状态变化时执行具体的业务逻辑。比如支付成功后,要更新状态、发送短信通知、记录日志等。

  • 监听器

监控状态机的每一步变化。比如状态改变时、事件触发时,都能触发到指定的回调方法。

  • 持久化支持

把状态机的当前状态保存到数据库。这样当服务重启后,工作流也能从上次中断的地方继续执行。

3 将 Spring Statemachine 作为一个轻量级工作流引擎来使用

下面就以电商订单的工作流为例,演示如何将业务流程建模为一个状态机,定义清晰的状态和事件,使用 Spring Statemachine 框架来驱动整个流程的自动化。

[DRAFT] -- CREATE 事件 --> [CREATED] -- PAY 事件 --> [PAID] -- SHIP 事件 --> [SHIPPED] -- DELIVER 事件 --> [DELIVERED]

3.1 定义状态和事件(States & Events)

电商订单对应的状态和事件类如下:

public enum OrderStates {
    DRAFT,
    CREATED,
    PAID,
    SHIPPED,
    DELIVERED
}
public enum OrderEvents {
    CREATE,
    PAY,
    SHIP,
    DELIVER
}

3.2 配置流程规则(Transitions)

这是构建工作流引擎最核心的一步。我们需要通过代码将这些状态(States)和事件(Events)连接起来,形成明确的流转规则。在配置类上使用 @EnableStateMachineFactory 注解,可以为每个流程实例(如每个订单)创建独立的状态机。

@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig
        extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {

    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config)
            throws Exception {
        config.withConfiguration()
                .autoStartup(true);
    }

    @Override
    public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)
            throws Exception {
        states.withStates()
                .initial(OrderStates.DRAFT)
                .states(EnumSet.allOf(OrderStates.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions)
            throws Exception {
        transitions.withExternal()
                .source(OrderStates.DRAFT).target(OrderStates.CREATED).event(OrderEvents.CREATE)
                .and()
                .withExternal()
                .source(OrderStates.CREATED).target(OrderStates.PAID).event(OrderEvents.PAY)
                .and()
                .withExternal()
                .source(OrderStates.PAID).target(OrderStates.SHIPPED).event(OrderEvents.SHIP)
                .and()
                .withExternal()
                .source(OrderStates.SHIPPED).target(OrderStates.DELIVERED).event(OrderEvents.DELIVER);
    }
}

3.3 配置多实例服务(Multi-instance Service)

因为不同的订单实例需要对应不同的 StateMachine 实例,所以配置一个 OrderStateMachineServiceConfig 类,指定 StateMachineService 获取的 StateMachine 实例是从 StateMachineFactory 获取的。

@Configuration
public class OrderStateMachineServiceConfig extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {

    @Bean
    public StateMachineService<OrderStates, OrderEvents> stateMachineService(
            StateMachineFactory<OrderStates, OrderEvents> stateMachineFactory) {
        return new DefaultStateMachineService<>(stateMachineFactory);
    }
}

3.4 封装事件发送方法(Events Sending Method)

流程的流转是通过发送事件来驱动的,下面我们在 OrderService 接口定义一个统一的事件发送方法:

public interface OrderService {
    void sendEvent(Long orderId, OrderEvents event);
}

并对该方法进行实现:

@Service
public class OrderServiceImpl implements OrderService {

    @Override
    public void sendEvent(Long orderId, OrderEvents event) {
        StateMachine<OrderStates, OrderEvents> stateMachine = stateMachineService.acquireStateMachine(String.valueOf(orderId));

        Message<OrderEvents> message = MessageBuilder
                .withPayload(event)
                .setHeader("orderId", orderId)
                .build();

        stateMachine.sendEvent(message);
    }
}

可以看到,事件发送方法中,StateMachine 实例统一从 StateMachineService 获取。发送的消息体带上了 orderId

封装好后,在业务代码(如 Service 层)中,就可以通过向状态机发送事件来驱动流程前进了。

3.5 配置监听器(Listener)

创建一个 OrderStateMachineListener 类,使用 @OnTransition 注解来监听状态变化并执行对应的业务逻辑。这比将业务代码写在 Service 层更符合工作流引擎的设计理念。

@Component
@WithStateMachine
public class OrderStateMachineListener {

    @OnStateChanged
    public void onStateChange(StateContext<OrderStates, OrderEvents> context) {
        Message<OrderEvents> message = context.getMessage();

        if (null != message) {
            Long orderId = message.getHeaders().get("orderId", Long.class);
            OrderStates targetState = context.getTarget().getId();

            // update state
            orderService.updateState(orderId, targetState);

            // other logic
            // ...
        }
    }
}

一旦有任何订单状态的变更,OrderStateMachineListener 类的 onStateChange 方法都能监听到。这样,一些诸如 Order 状态的更新以及状态变更后需要执行的业务逻辑都能放到这里。

3.6 发送事件驱动流程流转(Sending Events)

上面的准备工作做好后,现在即可通过调用封装好的事件发送方法,发送事件来推动整个流程的运转。

orderService.sendEvent(orderId1, OrderEvents.CREATE);

这样,OrderStateMachineListener 中的逻辑即会被触发。

3.7 状态持久化与恢复(State Persistence、Restore)

对于一个可靠的工作流引擎来说,服务重启后流程必须能从断点处恢复,这是至关重要的一步。

因此,我们需要优化 OrderService 中的事件发送方法:

@Service
public class OrderServiceImpl implements OrderService {

    @Override
    public void sendEvent(Long orderId, OrderEvents event) {
        StateMachine<OrderStates, OrderEvents> stateMachine = stateMachineService.acquireStateMachine(String.valueOf(orderId));

        OrderStates currentState = stateMachine.getState().getId();
        OrderStates state = orderRepository.getState(orderId);
        if (currentState != state) {
            restoreState(stateMachine, orderId, state);
        }

        Message<OrderEvents> message = MessageBuilder
                .withPayload(event)
                .setHeader("orderId", orderId)
                .build();

        stateMachine.sendEvent(message);
    }

    private void restoreState(StateMachine<OrderStates, OrderEvents> stateMachine, Long orderId, OrderStates state) {
        stateMachine.getStateMachineAccessor()
                .doWithAllRegions(access -> {
                    StateMachineContext<OrderStates, OrderEvents> context =
                            new DefaultStateMachineContext<>(
                                    state,
                                    null,
                                    null,
                                    null,
                                    null,
                                    String.valueOf(orderId)
                            );

                    access.resetStateMachine(context);
                });
    }
}

在发送事件前,需要判断 StateMachine 的当前状态是否与数据库中订单的最新状态一致,不一致要以数据库中的状态为准,然后接着推送流程的运转。

这样,流程走到任何一步遇到服务重启时都能接着正确的运行。

4 小结

综上,本文首先介绍了 State Machine 的概念;接着介绍了 Spring Statemachine 的作用;最后以电商订单的状态流转为例,演示了使用 Spring Statemachine 充当轻量级工作流引擎的可行性。

初步来看,Spring Statemachine 还是很强大的,其设计支持多流程实例、支持以配置的方式定义状态流转规则、支持以监听器的方式接收状态变更信号。是简单工作流场景的一个可选的实现引擎。

本文完整示例工程代码已提交至 GitHub,欢迎有需要的同学参考。

参考资料

[1] Spring: Spring Statemachine Reference Documentation - https://docs.spring.io/spring-statemachine/docs/4.0.1/reference/index.html