graph - 节点的拦截、监听与 AOP
有时候,当我们需要为流程节点统一添加性能监控、执行日志、权限校验或者全局异常处理时,不需要在每个组件里写重复代码。利用拦截器(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 的高阶排兵布阵——《并行、聚合与循环:复杂网关的底层逻辑》。看引擎如何通过内部栈结构处理复杂的循环遍历!