Solon v3.8.0

graph - 节点的拦截、监听与 AOP

</> markdown
2026年1月5日 上午10:30:50

有时候,当我们需要为流程节点统一添加性能监控、执行日志、权限校验或者全局异常处理时,不需要在每个组件里写重复代码。利用拦截器(FlowInterceptor),我们可以为节点修筑起一层强大的“影子逻辑”。

1、为什么需要拦截器?

在复杂的业务流程中,我们经常需要处理一些与核心业务无关、但又必不可少的逻辑:

  • 日志审计:记录谁在什么时候执行了哪个节点,耗时多久。
  • 参数预处理:进入节点前,统一校验上下文中的必要变量。
  • 通用容错:当节点执行失败时,统一记录错误码或触发重试机制。

通过拦截器,这些逻辑可以像“影子”一样附着在节点之上,实现业务逻辑与治理逻辑的彻底解耦。

2、核心 API:FlowInterceptor 机制

在 Solon-Flow 中,如果说 Node(节点)是身体,Link(连线)是经络,那么 FlowInterceptor(拦截器)就是“监控探头”和“外挂装甲”。

它通过 AOP(面向切面编程) 机制,让你在不修改业务代码的情况下,统一解决以下问题:

  • 审计:谁执行了哪个节点?耗时多久?
  • 安全:当前上下文环境是否允许进入该节点?
  • 治理:统一的异常处理、全局流水号注入。

最新版的 FlowInterceptor 将“流程拦截”与“节点监听”合二为一,提供了三个维度的控制:

维度对应方法作用范围典型场景
AOP 拦截doFlowIntercept全图/子图整体耗时统计、事务开启、全局上下文准备。
进入钩子onNodeStart每个节点执行前权限校验、输入参数日志、分支阻断。
退出钩子onNodeEnd每个节点执行后输出参数审计、节点状态持久化。

3、实战演练:编写你的第一个拦截器

我们将通过一个“执行链路追踪器”来展示其强大的控制力。

第一步:编写拦截器类

import org.noear.solon.annotation.Component;
import org.noear.solon.flow.FlowContext;
import org.noear.solon.flow.FlowException;
import org.noear.solon.flow.Node;
import org.noear.solon.flow.intercept.FlowInterceptor;
import org.noear.solon.flow.intercept.FlowInvocation;

@Component
public class TraceInterceptor implements FlowInterceptor {
    /**
     * AOP 拦截:包裹了整个 FlowEngine.eval() 的执行过程
     */
    @Override
    public void doFlowIntercept(FlowInvocation invocation) throws FlowException {
        // 1. 执行前逻辑
        long start = System.currentTimeMillis();

        // 2. 触发后续链条(包含其他拦截器和真正的节点执行)
        invocation.invoke();

        // 3. 执行后逻辑
        System.out.println("流程 [" + invocation.getGraph().getId() + "] 执行完毕,耗时:" + (System.currentTimeMillis() - start) + "ms");
    }

    /**
     * 节点进入监听:在每个节点 Task 执行前触发
     */
    @Override
    public void onNodeStart(FlowContext context, Node node) {
        // 通过 context 拿到交换器,实现运行时干预
        if ("sensitive_task".equals(node.getId())) {
            System.out.println("检测到敏感节点,检查权限...");
            // 如果校验失败,可以调用 context.exchanger().interrupt(true) 阻断当前分支
        }
    }
}

第二步:注册到引擎

拦截器支持 Rank 排序,数值越小优先级越高。

@Configuration
public class FlowConfig {
    @Bean
    public void initEngine(FlowEngine engine, TraceInterceptor trace) {
        // 注册全局拦截器,排序号为 1
        engine.addInterceptor(trace, 1);
    }
}

4、关键点:运行时阻断逻辑

这是拦截器最强大的功能之一。根据 FlowEngine 的底层逻辑,你在 onNodeStart 中的操作可以直接影响执行引擎的行为:

  • context.stop():立即停止整个流程图。适用于发现致命错误或全局熔断。
  • context.interrupt():仅阻断当前这条线。如果此时有并行节点在运行,它们不会受影响。

5、常见问题 (FAQ)

Q:拦截器里抛出异常会怎样? A:异常会沿着 FlowInvocation 链条向上抛出。除非你手动 try-catch,否则流程会因为异常而中断,这正是实现“校验失败即停机”的理想方式。

Q:拦截器是线程安全的吗? A:拦截器本身是单例注册的,但 onNodeStart 等方法传入的是当前线程的 FlowContext 和 Node,因此它是线程隔离的,你可以安全地在方法内部处理业务数据。

6、学习小结

  • 全局控制找 doFlowIntercept。
  • 精细监控找 onNodeStart/End。
  • 注册记得设置 Rank 权重。

后续,我们将挑战 Solon-Flow 的高阶排兵布阵——《并行、聚合与循环:复杂网关的底层逻辑》。看引擎如何通过内部栈结构处理复杂的循环遍历!