当技术具有了情怀:认识 LingFrame——一个为老系统“续命”的 JVM 治理框架
当技术具有了情怀:认识 LingFrame——一个为老系统“续命”的 JVM 治理框架
写在前面
如果你也是一个 Java 开发者,你一定见过这样的系统:
它已经跑了五六年,代码庞大到没人敢动。每一次上线都像在黑夜中摸索,每一次发布都伴随着祈祷。你想重构,但业务不允许停下;你想拆分微服务,但成本和风险都太高。
于是它就这么跑着,像一个越来越臃肿、越来越脆弱的老人,你知道它总有一天会出问题,但你无能为力。
直到我遇到了 LingFrame (点击下方链接访问)。
📦 项目地址
GitCode
https://gitcode.com/lingframe/LingFrame
Gitee
https://gitee.com/knight6236/lingframe
GitHub
https://github.com/LingFrame/LingFrame

一、一个不一样的 README
第一次看到 LingFrame 的 README,我愣了一下。
它不是从“如何集成”开始的,而是这样写的:
“很多系统并不是设计得不好,只是活得太久,改得太急。”
“每一次改动都像在黑夜中摸索,每一次上线都伴随着祈祷。”
这段话击中了我。它说的不就是我们每天都在面对的现实吗?
这个项目叫 LingFrame(灵珑),一个面向长期运行系统的 JVM 运行时治理框架。
但让我决定深入了解的,不是它的技术特性,而是它的气质——它似乎真的懂那些在老旧系统里挣扎的程序员。
二、🔍 LingFrame 是什么:给 Spring Boot 装上“治理内核”
LingFrame · 灵珑
| 项目核心信息 | 兼容版本支持 | 代码仓库地址 | 参与贡献 |
|---|---|---|---|
| 🟢 状态:核心功能已实现 📜 许可证:Apache 2.0 |
🟠 Java:8 / 17 🟢 Spring Boot:2.7.18 / 3.5.6 |
🔴 Gitee 主仓库 ⚪ AtomGit G-Star 孵化项目 ⚫ GitHub 镜像仓库 |
🎉 PRs 欢迎提交 💡 DeepWiki 技术问答 |
🎯 一句话概括
这个项目叫 LingFrame(灵珑)
一个JVM 运行时安全治理解决方案。
它不做微服务那样的物理拆分(不需要网络调用,没有分布式事务的烦恼),而是在逻辑上帮你把业务模块拆分成 独立的单元(Ling)。
🧩 什么是“单元”?
可以把“单元”理解成一个轻量级的、可热插拔的 Spring Boot 应用:
| 维度 | 说明 | 对开发者的意义 |
|---|---|---|
| 类加载器 | 每个单元拥有独立的 ClassLoader | 再也不用担心 jar 包冲突,不同单元可以用不同版本的依赖 |
| Spring 上下文 | 每个单元有完全独立的 ApplicationContext | Bean 不会互相污染,一个单元的 @Component 扫不到另一个单元里去 |
| 生命周期 | 可独立加载、启动、停止、卸载 | 出问题的单元可以单独干掉,不影响主系统 |
| 版本管理 | 支持同一单元多版本共存 | 蓝绿部署、A/B 测试天然支持 |
| 治理策略 | 每个单元可配置独立的权限、熔断、限流规则 | 高风险的单元可以限制得更严,核心单元保障高可用 |
这意味着什么?
你可以在不重启整个应用的情况下:
- 给订单模块单独升级
- 给用户模块单独回滚
- 给支付模块单独加权限控制
- 让 10% 的用户先体验新版本的功能
🏗️ 三层架构:谁负责什么,边界在哪
LingFrame 的核心是三层架构,每一层职责单一,像操作系统一样清晰:

💡 这个架构想明白了什么?
第一,Core 不做业务。
这是最关键的决策。Core 里没有任何业务代码,它只做三件事:调度、仲裁、记录。就像操作系统的内核,不关心你是写文档还是打游戏,只负责分配 CPU 时间片、管理内存、记录日志。
好处是什么?Core 可以保持稳定,不会因为业务变化而频繁修改。它一旦稳定下来,就可以成为整个系统的“信任基座”。
第二,所有跨单元调用必须经过 Core。
这意味着:没有后门可走。A 单元想调 B 单元的服务?必须经过 Core。A 单元想查数据库?必须经过 Core。每一条调用链路都在 Core 的掌控之下。
第三,基础设施也被“代理”了。
业务单元不能直接操作数据库、Redis,而是通过 Infrastructure 层的代理。这些代理在真正执行操作之前,会先问 Core:“这个单元有权限这么做吗?” Core 查一下配置,说“可以”才放行,说“不行”就直接拦下。
三、它是怎么做到的:技术思路拆解
1. 🧱 类加载隔离:解决“jar 包冲突”的思路
要解决的问题:
一个系统里,订单模块用 FastJSON 1.x,支付模块用 FastJSON 2.x。如果放在同一个 ClassLoader 里,必然冲突,总有一个模块会报 NoSuchMethodError。
LingFrame 的思路:
让每个单元用自己的 ClassLoader 加载自己的依赖,互不干扰。
但这里有个坑:如果两个单元之间要传对象(比如 UserDTO),这个对象由谁加载?A 的 ClassLoader 加载的 UserDTO,B 的 ClassLoader 不认识,一传就报 ClassCastException。
解法:
把接口和 DTO 单独抽出来,放到一个“共享区域”,由所有单元共用的父 ClassLoader 加载。业务实现类(有版本冲突风险的)由各自的 ClassLoader 加载。
这样:
- 订单单元用的 FastJSON 1.x,支付单元用的 FastJSON 2.x,互不影响 ✅
- 两个单元传的 UserDTO 是同一个 ClassLoader 加载的,不会类型转换异常 ✅
配置方式:
在 application.yaml 里告诉框架,哪些 jar 是共享 API:
lingframe:
preload-api-jars:
- libs/order-api.jar # 订单模块的接口和 DTO
- libs/user-api.jar # 用户模块的接口和 DTO
- libs/*-api.jar # 支持通配符
2. 🌱 Spring 上下文隔离:不是父子,是兄弟
要解决的问题:
每个单元需要有自己的 Spring 容器,但如果用传统的父子上下文,子容器可以拿到父容器的 Bean,这就绕过了权限控制。而且父容器持有子容器的引用,单元卸载时无法释放内存。
LingFrame 的思路:
每个单元的 Spring 上下文都是完全独立的,和 Core 的上下文没有父子关系。
单元 A 的 Bean 拿不到 Core 的 Bean,单元 B 的 Bean 也拿不到单元 A 的 Bean。想调用别人的服务?必须通过 @LingReference 走代理,不能直接 @Autowired。
这样:
- 权限控制不会被绕过 ✅
- 单元卸载时没有引用残留,可以被 GC 回收 ✅
- 每个单元可以有自己的配置、自己的 Bean,完全隔离 ✅
3. 🔌 跨单元调用:@LingReference 的设计思路
要解决的问题:
订单单元想调用户单元的服务,最直接的方式是 @Autowired 一个 UserService,但这样有耦合,而且用户单元可能还没启动。
LingFrame 的思路:
用 @LingReference 注入一个代理对象,真正调用时才去解析目标单元。
这个设计妙在哪里?
| 特性 | 说明 | 对开发者的好处 |
|---|---|---|
| 延迟绑定 | 调用发生时才去找目标单元 | 单元启动顺序无关,A 启动时 B 没启动也不报错 |
| 智能路由 | 可以根据配置决定调哪个版本 | 灰度发布、A/B 测试天然支持 |
| 治理拦截 | 调用前自动做权限检查、熔断判断 | 业务代码里不用写这些重复逻辑 |
使用体验:
@Component
public class OrderService {
@LingReference
private UserQueryService userQueryService; // 就像调本地方法
public Order createOrder(String userId) {
// 这一行背后:权限检查、审计日志、可能还有熔断判断
UserDTO user = userQueryService.findById(userId);
return new Order(user);
}
}
4. 🛡️ 基础设施代理:零信任的落地思路
要解决的问题:
业务单元应该只能做它被允许做的事。比如用户单元可以查数据库(读),但不能删表(写)。但常规的 Spring 应用里,只要有了 DataSource,什么 SQL 都能执行。
LingFrame 的思路:
在业务单元和基础设施之间加一层代理,所有操作必须经过代理的检查。
以数据库为例:
当业务单元执行 userRepository.findById(1L) 时,真实发生的流程是:
- 框架自动包装的
LingDataSource接管了调用 - 它从线程上下文里拿到“谁在调”(user-ling 单元)
- 解析要执行的 SQL 类型(SELECT 是读操作)
- 问 Core:“user-ling 有数据库读权限吗?”
- 有权限 → 放行,执行真正的查询
- 没权限 → 直接抛异常,SQL 根本不会执行
整个过程对业务代码完全透明,开发者写 userRepository.findById() 时,根本感知不到这些拦截。
缓存也是同理:
redisTemplate.opsForValue().set(key, value) 会被拦截,框架根据方法名(set)推导出是写操作,检查权限后再决定是否放行。
5. 🔐 权限治理:声明式 + 智能推导的思路
要解决的问题:
每个单元需要什么权限,应该明确说出来,而不是在代码里到处写 if(check)。
LingFrame 的思路:
单元在 ling.yml 里声明自己需要哪些权限:
governance:
permissions:
- capability: "storage:sql" # 数据库操作
permission: "READ" # 只读
- capability: "cache:redis" # Redis 操作
permission: "WRITE" # 可写
如果没声明怎么办?
框架会“智能推导”。比如方法名叫 findUserById,推导为读操作;叫 createUser,推导为写操作。推导规则可配置,也可以完全关闭,强制要求显式声明。
开发模式 vs 生产模式:
- 开发模式:权限不足时只警告,不阻断。避免调试时频繁被打断。
- 生产模式:严格执行,权限不足直接拒绝。
这个细节体现了对开发者的体谅——既要安全,又不影响开发效率。
6. 🔄 蓝绿部署与灰度发布:不停机的思路
要解决的问题:
新功能上线,万一出问题怎么办?能不能只让一部分用户先试?
LingFrame 的思路:
单元支持多版本共存。安装新版本时,旧版本继续处理已有请求;新版本启动完成后,新请求切换到新版本;旧版本等请求处理完再卸载。
灰度发布的配置方式:
canary:
enabled: true
rules:
- type: "percentage" # 按百分比
value: 10 # 10% 流量
targetVersion: "2.0.0" # 走新版本
- type: "header" # 按请求头
key: "X-User-Tag"
value: "beta"
targetVersion: "2.0.0"
7. ⚡ 弹性治理:熔断、限流、重试的思路
要解决的问题:
一个单元出问题,不能让它拖垮整个系统。调用量突增时,不能把后端打爆。
LingFrame 的思路:
内置一套完整的弹性治理能力,对业务代码完全透明:
| 能力 | 实现思路 | 配置方式 |
|---|---|---|
| 熔断 | 滑动窗口统计错误率,超阈值后自动断开 | circuit-breaker: enabled: true |
| 限流 | 令牌桶算法,控制请求速率 | rate-limiter: permits-per-second: 100 |
| 重试 | 失败自动重试,可配置退避策略 | retry: max-attempts: 3 |
| 超时 | 每个服务可单独配置超时时间 | @LingService(timeout = 3000) |
这些能力都在代理层自动完成,业务代码里写的是纯业务逻辑,不需要关心这些横切关注点。
四、为什么说它有“情怀”
技术层面讲完了,我想聊聊它给我的另一种感受。
LingFrame 的文档里有很多“不像技术文档”的话:
“你不需要一次性读完所有内容。灵珑允许你在任何阶段停下。”
“灵珑不会替系统做决定。她只是在系统还愿意被理解的时候,帮你把事情放回该在的位置上。”
“如果你只是走到这里停下,那也完全没有关系。”
这些话让我觉得,这个项目的作者真的在乎使用它的人。
很多开源项目追求“功能强大”、“性能极致”,但 LingFrame 在追求这些的同时,还在追求另一件事:让开发者少受一点苦。
它的设计处处体现着这一点:
| 设计 | 背后的体谅 |
|---|---|
| 开发模式 | 权限不足只警告不阻断,知道你在调试,不打断你 |
| 消费者驱动契约 | 谁需要能力谁定义接口,不用被迫适配别人的全量接口 |
| @LingReference 延迟绑定 | 单元启动顺序无关,A 启动时 B 没启动也不报错 |
| 三层 ClassLoader | 帮你解决 jar 包冲突,不用自己折腾 |
| 异步审计 | 不阻塞业务调用,性能影响降到最低 |
这些不是“技术难点”,而是“开发者痛点”。LingFrame 在意的,正是这些。
五、我为什么参与进来
我承认,最开始是被它的“气质”吸引的。
但在使用的过程中,我发现它的技术设计同样扎实。三层架构清晰,文档完整(甚至可以说优美),代码质量高,issue 响应及时。
于是我开始提 PR。
从一个小的文档修正,到一个功能的讨论,再到更深度的参与。我发现这个项目的社区氛围和它的代码一样——尊重人。
没有那种“你不行”的高傲,没有“爱用不用”的冷漠。讨论技术问题时,大家关注的是“怎样对使用者更好”。
这让我想起 README 里的那句话:
“灵珑存在的意义,是在系统复杂到某个阶段时,为‘回缩’与‘重组’提供可能性。”
它给老系统“续命”,也在给开发者“减负”。
六、如果你想了解更多
LingFrame 目前已经实现了:
| 阶段 | 核心能力 | 状态 |
|---|---|---|
| Phase 1 | 核心治理:权限、审计、单元隔离 | ✅ 已完成 |
| Phase 2 | 可视化:Dashboard 治理中心 | ✅ 基本完成 |
| Phase 3 | 弹性治理:熔断、降级、重试、限流 | ✅ 已完成 |
| Phase 4 | 可观测性:指标采集、调用链可视化 | ⏳ 计划中 |
| Phase 5 | 基础设施扩展:消息代理、搜索代理 | ⏳ 计划中 |
🚀 快速体验
# 克隆代码
git clone https://gitee.com/knight6236/lingframe.git
# 编译安装
cd lingframe
mvn clean install -DskipTests
# 启动示例应用
cd lingframe-examples/lingframe-example-lingcore-app
mvn spring-boot:run
启动后访问:http://localhost:8888/dashboard.html,就可以看到效果。
更详细的教程在 getting-started.md,5 分钟就能跑起来。
七、欢迎一起参与
LingFrame 还在成长中。
如果你也被老系统折磨过,如果你想了解一种不一样的治理思路,欢迎来看看。
如果你觉得这个方向有意义,也欢迎参与贡献——可以是代码,可以是文档,可以是 issue 讨论,甚至只是点个 Star。
文档里有一句话我很喜欢,用它来结尾吧:
“LingFrame 不要求你一开始就‘治理一切’。”
“它只是让你在系统失控之前,多一次选择的机会。”
欢迎在评论区交流讨论!
更多推荐





所有评论(0)