做后台开发的同学一定遇到过这类需求:请假审批:员工提交 -> 主管审批 -> 部门经理审批 -> 副总审批,但不同天数的审批链路还不一样合同审批:金额超过 10 万需要额外部门会签,超过 50
做后台开发的同学一定遇到过这类需求请假审批员工提交 - 主管审批 - 部门经理审批 - 副总审批但不同天数的审批链路还不一样合同审批金额超过 10 万需要额外部门会签超过 50 万需要财务参与数据抓取多线程并行爬取多个数据源再汇总处理这类需求本质上都是一个有向图的流转问题。如果全靠 if-else 硬编码代码很快就会变成面条式意大利粉。Solon Flow是 Solon 生态中的通用流程编排框架它的核心思路是用 YAML或 Java Fluent API描述流转逻辑用引擎驱动执行。不需要重依赖、不需要外部数据库、不需要部署服务一个 jar 包就能跑。今天这篇文章我们用最经典的请假审批流作为实战案例从零到一跑通 Solon Flow 的核心能力。二、5 分钟跑起来Hello World2.1 添加依赖在pom.xml中添加dependency groupIdorg.noear/groupId artifactIdsolon-flow/artifactId /dependency不需要额外数据库、不需要消息中间件一个依赖搞定。2.2 创建流程定义文件在resources/flow/目录下创建demo1.ymlid: demo1 layout: - { id: s, type: start, link: n1 } - { id: n1, type: activity, task: System.out.println(hello world!);, link: e } - { id: e, type: end }这是一个最简单的三节点流程开始 - 执行打印 - 结束。2.3 执行两种方式任选其一方式一原生 Java 模式不需要启动 Solon 容器import org.noear.solon.flow.FlowEngine; public class Demo { public static void main(String[] args) { FlowEngine engine FlowEngine.newInstance(); engine.load(classpath:flow/*); engine.eval(demo1); // 控制台输出hello world! } }方式二Solon 容器注解模式先在应用配置中声明流程文件位置# app.yml solon.flow: - classpath:flow/*.yml然后在组件中注入引擎直接使用Component public class DemoCom implements LifecycleBean { Inject private FlowEngine flowEngine; Override public void start() throws Throwable { flowEngine.eval(demo1); } }运行后控制台输出hello world!。5 分钟一个流程就跑通了。三、核心概念速览7 种节点 引擎 上下文在进入实战之前先过一遍 Solon Flow 的核心概念。这些概念非常精简但足够覆盖绝大多数编排场景。3.1 七种节点类型Solon Flow 的图由7 种节点构成节点类型说明执行任务连接条件多线程可流入可流出start开始节点---01activity活动节点缺省类型支持--1..n1..nexclusive排他网关单选支持支持-1..n1..ninclusive包容网关多选支持支持-1..n1..nparallel并行网关全选支持-支持1..n1..nloop循环网关支持--11end结束节点---1..n0几个关键点start和end每个图必须有且仅有一个exclusive排他网关相当于单选只有一条满足条件的连接会流出没有匹配的用默认无条件连接inclusive包容网关相当于多选所有满足条件的连接都会流出需要成对使用实现汇聚parallel并行网关相当于全选所有连接都会流出内部使用多线程执行需要成对使用实现汇聚loop循环网关遍历集合并循环流出通过$for和$in元数据指定变量3.2 流程引擎FlowEngineFlowEngine是执行流程的核心入口主要负责加载和解析流程定义支持 YAML、JSON、Java 硬编码驱动流程执行管理拦截器链FlowEngine engine FlowEngine.newInstance(); engine.load(classpath:flow/*.yml); // 加载 engine.eval(demo1); // 执行按 id 匹配 engine.eval(demo1, context); // 执行带上下文 engine.eval(demo1, 1, context); // 执行深度控制单步调试3.3 上下文FlowContextFlowContext是流程执行的核心现场承载了业务数据、控制状态和执行轨迹// 创建 FlowContext context FlowContext.of(); FlowContext context FlowContext.of(instance-001); // 传递业务参数 context.put(day, 5); context.put(applicant, 张三); // 获取参数 int day context.getAs(day); // 控制流程 context.stop(); // 停止可用于中断恢复 context.interrupt(); // 中断当前分支 // 序列化与恢复 String snapshot context.toJson(); FlowContext restored FlowContext.fromJson(snapshot); // 执行轨迹 context.lastNodeId(); // 最后执行的节点 ID context.trace(); // 完整执行轨迹概念不多但覆盖了编排、执行、控制、恢复四大核心能力。下面进入实战。四、实战一50 行 YAML 实现请假审批流条件分支 exclusive4.1 业务规则一个请假审批的流转规则如下员工发起请假 - 主管审批 - 天数 3天直接结束主管批了就行 - 天数 3天部门经理审批 - 天数 7天结束 - 天数 7天副总审批 - 结束这是一个典型的条件分支场景用exclusive排他网关来实现。4.2 流程定义创建resources/flow/leave-approval.ymlid: leave-approval title: 请假审批 layout: - { id: s, type: start, title: 发起人, meta: { role: employee }, link: n1 } - { id: n1, type: activity, title: 主管审批, task: tl_approve, link: g1 } - { id: g1, type: exclusive, title: 天数判断, link: [ { nextId: e, title: 3天以下 }, { nextId: n2, title: 3天以上, when: day3 } ]} - { id: n2, type: activity, title: 部门经理审批, task: dm_approve, link: g2 } - { id: g2, type: exclusive, title: 天数判断, link: [ { nextId: e, title: 7天以下 }, { nextId: n3, title: 7天以上, when: day7 } ]} - { id: n3, type: activity, title: 副总审批, task: vp_approve, link: e } - { id: e, type: end }一共 8 个节点含 start 和 endYAML 共50 行以内。解释几个关键点task: tl_approve以开头的是任务组件引用对应 Java 中注册的TaskComponentwhen: day3连接条件表达式引擎通过表达式引擎SnEL求值day从上下文中获取排他网关g1如果day3满足走n2否则走默认连接e没有 when 的连接就是默认meta: { role: employee }元数据可以在拦截器或任务中读取用于权限判断等4.3 任务组件实现每个task中的xxx引用对应一个 Java 组件import org.noear.solon.flow.core.TaskComponent; import org.noear.solon.flow.core.FlowContext; import org.noear.solon.flow.core.Node; // 主管审批 Component(tl_approve) public class TeamLeaderApprove implements TaskComponent { Override public void run(FlowContext context, Node node) throws Throwable { String applicant context.getAs(applicant); int day context.getAs(day); System.out.println(主管审批通过申请人 applicant , 天数 day); context.put(tl_approved, true); } } // 部门经理审批 Component(dm_approve) public class DeptManagerApprove implements TaskComponent { Override public void run(FlowContext context, Node node) throws Throwable { String applicant context.getAs(applicant); System.out.println(部门经理审批通过申请人 applicant); context.put(dm_approved, true); } } // 副总审批 Component(vp_approve) public class VPApprove implements TaskComponent { Override public void run(FlowContext context, Node node) throws Throwable { String applicant context.getAs(applicant); System.out.println(副总审批通过申请人 applicant); context.put(vp_approved, true); } }4.4 测试运行public class LeaveApprovalTest { public static void main(String[] args) { FlowEngine engine FlowEngine.newInstance(); engine.load(classpath:flow/leave-approval.yml); // 场景1请假2天 - 主管审批 - 结束 FlowContext ctx1 FlowContext.of() .put(applicant, 张三) .put(day, 2); engine.eval(leave-approval, ctx1); // 输出主管审批通过申请人张三, 天数2 // 场景2请假5天 - 主管 - 部门经理 - 结束 FlowContext ctx2 FlowContext.of() .put(applicant, 李四) .put(day, 5); engine.eval(leave-approval, ctx2); // 输出主管审批通过... 部门经理审批通过... // 场景3请假10天 - 主管 - 部门经理 - 副总 - 结束 FlowContext ctx3 FlowContext.of() .put(applicant, 王五) .put(day, 10); engine.eval(leave-approval, ctx3); // 输出主管审批通过... 部门经理审批通过... 副总审批通过... } }这就是完整的请假审批流。50 行 YAML 几个任务组件流转逻辑一目了然。五、实战二并行网关 — 同时发送短信和邮件通知审批通过后需要同时给申请人和 HR 发送短信通知和邮件通知。这是一个典型的并行执行场景用parallel并行网关来实现。id: notify-flow title: 审批通知 layout: - { id: s, type: start, link: n1 } - { id: n1, type: activity, title: 审批完成, task: after_approve, link: g1 } - { id: g1, type: parallel, title: 并行发送, link: [n2, n3] } - { id: n2, type: activity, title: 发送短信, task: send_sms, link: g2 } - { id: n3, type: activity, title: 发送邮件, task: send_email, link: g2 } - { id: g2, type: parallel, title: 汇聚结果, link: e } - { id: e, type: end }关键说明

相关新闻

Visual Studio 中的 Agent Skill:让 Copilot 适配团队工作模式

Visual Studio 中的 Agent Skill:让 Copilot 适配团队工作模式

创建一项技能您可以直接在 Visual Studio 中创建技能。点击 Copilot Chat 窗口右下角的工具图标,即可打开技能面板,该面板会集中展示所有已发现的技能。点击面板右上角的 按钮,按照引导流程操作:选择保存位置(全局级别…

2026/6/26 1:12:23阅读更多 →
2026门店老板想用手机随时看数据?京东收银这套手机管店能力值得了解

2026门店老板想用手机随时看数据?京东收银这套手机管店能力值得了解

2026门店老板想用手机随时看数据?京东收银这套手机管店能力值得了解很多门店老板在选收银机时,已经不只问能不能收款,还会问一句:哪个牌子收银机有云端后台,能不能用手机随时看门店数据?这个需求背后&#…

2026/6/26 1:12:23阅读更多 →
铁电MEMS突触技术:神经形态计算新突破

铁电MEMS突触技术:神经形态计算新突破

1. 铁电MEMS突触技术背景与核心创新 神经形态计算作为模拟生物神经系统的新型计算范式,其核心挑战在于实现类似生物突触的模拟权重存储与更新机制。传统铁电突触器件(如FeFET、FeCAP等)通过铁电材料的剩余极化(Pr)状态存储权重信息&#xff0…

2026/6/26 1:12:23阅读更多 →
ChatGPT嵌入DAM系统:自然语言驱动数字资产智能操作

ChatGPT嵌入DAM系统:自然语言驱动数字资产智能操作

1. 项目概述:当ChatGPT真正“走进”数字资产管理系统你有没有过这样的经历:市场部同事急着要一张带“环保”“夏季”“户外”三个标签的高清产品图,但你翻了二十分钟文件夹,最后发现它被归在“2023_Q2_活动素材_备份_终版_v3_&…

2026/6/26 2:17:31阅读更多 →
ROS2上使用WeChatQRdetector扫码二维码

ROS2上使用WeChatQRdetector扫码二维码

微信的扫码算法对机器人在运动过程中产生的模糊、畸变有极强的识别率。ROS 2 社区有基于 OpenCV 编译的 wechat_qrcode 节点。 功能包推荐: ros2_wechat_qrcode 或自行编写节点调用 OpenCV 的 wechat_qrcode 模块。 工作流: 摄像头驱动节点发布图像话题…

2026/6/26 2:17:31阅读更多 →
OpenClaw调度框架深度解析

OpenClaw调度框架深度解析

如果你在用AI Agent做复杂任务,你一定遇到过这些问题:对话稍微长一点,AI就开始“犯糊涂”,回答越来越离谱明明用的是顶级模型,Token账单却比工资涨得还快某个模型突然限流或宕机,整个任务就卡住了不知道什么…

2026/6/26 2:17:31阅读更多 →
如何用BatteryML开源工具精准预测电池寿命:新手完整指南

如何用BatteryML开源工具精准预测电池寿命:新手完整指南

如何用BatteryML开源工具精准预测电池寿命:新手完整指南 【免费下载链接】BatteryML 项目地址: https://gitcode.com/gh_mirrors/ba/BatteryML BatteryML是微软开源的电池寿命预测机器学习框架,专门用于解决电池性能衰减预测难题。无论你是数据科…

2026/6/26 2:17:31阅读更多 →
Pearcleaner:深度解析macOS应用清理的现代Swift架构实现

Pearcleaner:深度解析macOS应用清理的现代Swift架构实现

Pearcleaner:深度解析macOS应用清理的现代Swift架构实现 【免费下载链接】Pearcleaner A free, source-available and fair-code licensed mac app cleaner 项目地址: https://gitcode.com/gh_mirrors/pe/Pearcleaner 你是否曾好奇macOS应用卸载后残留文件的…

2026/6/26 2:17:30阅读更多 →
抖音无水印批量下载终极方案:3步解决创作者素材管理难题

抖音无水印批量下载终极方案:3步解决创作者素材管理难题

抖音无水印批量下载终极方案:3步解决创作者素材管理难题 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback sup…

2026/6/26 2:12:30阅读更多 →
【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体 一文搞定到底什么是智能体【人工智能】一文搞定到底什么是智能体一. LM,WorkFlow,Agent分别有什么么不同二. Agent的思考过程是怎样的三. Agent的五个核心部分1)LLM2)Prompt3)Me…

2026/6/25 9:39:54阅读更多 →
嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

1. 嵌入式GUI控件:从原理到实战的深度解析在嵌入式系统开发中,图形用户界面(GUI)的设计与实现往往是项目从“能用”到“好用”的关键一跃。不同于资源充沛的PC或移动平台,嵌入式设备的GUI需要在有限的CPU性能、内存空间…

2026/6/25 2:52:24阅读更多 →
Google AI Studio 300美元额度的真相与实战指南

Google AI Studio 300美元额度的真相与实战指南

1. 这300美金不是“送钱”,而是Google埋下的第一道技术门槛 你看到标题里那个醒目的“$300美金”时,第一反应可能是:又一个免费额度?领完就完事?我亲手试过——这300美金根本不是红包,而是一张入场券&…

2026/6/25 9:01:34阅读更多 →
HPE (慧与) 服务器专用 ESXi 9 全套官方定制资源详解 + 完整部署升级教程

HPE (慧与) 服务器专用 ESXi 9 全套官方定制资源详解 + 完整部署升级教程

一、前言:企业运维痛点与资源价值自博通收购 VMware 之后,原 VMware 公开免费下载渠道全面关闭,企业运维人员想要获取适配 HPE 慧与服务器的 ESXi 9 原厂镜像,必须注册博通账号、绑定有效授权才能下载,无授权账号无法获…

2026/6/26 0:02:15阅读更多 →
Kotlin的@JvmStatic与@JvmField:与Java互操作的注解

Kotlin的@JvmStatic与@JvmField:与Java互操作的注解

Kotlin作为一门现代编程语言,与Java的互操作性一直是其核心优势之一。为了让Kotlin代码能够无缝对接Java,Kotlin提供了多种注解来优化互操作体验,其中JvmStatic和JvmField是两个关键注解。它们分别用于解决静态成员和字段在Java中的访问问题&…

2026/6/26 0:02:15阅读更多 →
深入解析musl libc中的mmap实现源码

深入解析musl libc中的mmap实现源码

最近在阅读musl libc源码时,发现其mmap的实现非常精妙,特分享给大家。 一、代码整体结构 这段代码实现了__mmap函数,并通过weak_alias导出为mmap。这是典型的musl libc风格——提供弱符号以便用户可以重写。 weak_alias(__mmap, mmap); 二…

2026/6/26 0:02:15阅读更多 →