从 UI 到内核:Oinone 的全栈可扩展方法论 — Hook/AOP/扩展点与 SPI 的实践
Oinone 把“每个需求都是一个独立模块、支持各业务线差异化扩展、从框架到组件可深度扩展”作为设计目标。体系由 四条纵向能力(交互、模型、函数、应用生命周期)与 两条横向机制(API 生命周期扩展、平台 SPI 扩展)构成,通过字段/函数重写、Hook/AOP、扩展点(前置/后置/覆盖)与主题/母版/视图/路由/动作等粒度化插拔,做到既能快速装配,也能深入定制。 1. 设计目标 模块化:每个需求都能被打包成独立模块,独立发布与回滚。 差异化:同一能力在不同业务线可走不同实现与配置。 深度扩展:不仅页面可配,模型、函数、生命周期乃至平台内核都可扩展。 演示环境 相关视频 ⚡ 直达演示环境 ☕ 账号:admin ☕ 密码:admin 🎬 1. [数式Oinone] #产品化演示# 后端研发与无代码辅助 🎬 2. [数式Oinone] #产品化演示# 前端开发 🎬 3. [数式Oinone] #个性化二开# 后端逻辑 🎬 4. [数式Oinone] #个性化二开# 前端交互 🎬 5. [数式Oinone] #个性化二开# 无代码模式 2. 总体框架 Oinone 的扩展体系可以概括为: 四条纵向能力 交互可扩展:主题、母版(布局)、视图、字段组件、路由、动作均可增加/替换/指定/组合。 模型可扩展:支持字段重写、增强模型与五类继承(抽象继承、扩展继承、代理继承、多表继承、临时继承)。 函数可扩展:函数重写、Hook 机制(AOP)、扩展点机制(前置/后置/覆盖)。 应用生命周期可扩展:模块安装/升级/重启逻辑,以及构建前/构建后、生命周期前/生命周期后的处理逻辑与元数据编排。 两条横向机制 基于 API 的生命周期扩展:对应用层事件(安装、升级、重启等)开放 API,让模块声明自己的编排与执行。 基于 SPI 的平台能力扩展:网络协议层 SPI、驱动层 SPI、FaaS 层 SPI(执行约束 SPI、RPC 调用 SPI)、持久层 SPI、ORM 层 SPI 等,允许替换/新增底座能力。 3. 交互可扩展:把“界面设计”拆到最小颗粒 从“看得见”的地方降本增效,是扩展的第一现场。 主题可扩展:风格可增加/替换/切换,适配多租户、多品牌。 母版(布局)可扩展:页面框架可替换/指定,如后台与大屏使用不同母版。 视图可扩展:列表/表单/看板/图表等视图类型可增补,与数据模型绑定。 字段可扩展:字段组件可增加/替换/指定,如把文本框替换成带校验的选择器。 路由可扩展:路由表项可增加/替换,模块自带路径不必侵入主工程。 动作可扩展:动作可增加/替换/指定/组合,支持将“审批+发运”等复合动作编排为一步。 示例(片段) { "module": "po-approval", "views": { "PurchaseOrder.Detail": { "fields": { "expectedDate": { "component": "DatePicker", "override": true } }, "actions": [ { "id": "approveAndShip", "type": "compose", "steps": ["approve", "ship"] } ], "routes": [ { "path": "/po/:id/ship", "component": "ShipView" } ] } }, "theme": { "extends": ["theme:default"] } } 4. 模型可扩展:差异只写在差异处 模型层提供结构与行为的“正交”扩展: 字段重写:允许对已有字段的校验、渲染器、默认值进行重写。 增强模型:基于搜索/索引的查询增强、校验规则增强、派生字段等。 五类继承 抽象继承:提取公共字段/方法的抽象基类,不可直接实例化。 扩展继承:在不改变基类语义的前提下,向目标模型增量加字段/约束。 代理继承:行为转发/包装到另一个模型,便于隔离合规或跨域访问。 多表继承:一个逻辑模型映射多张表,支持冷热分层/历史归档。 临时继承:按租户/活动在运行期注入短期字段/规则,撤销即回退。 示例(伪 DSL) // 在 BaseOrder 上做扩展继承 model PurchaseOrder extends BaseOrder with ExtendsInheritance { @override field expectedDate: Date field supplierRating: Int? enhance { searchIndex "supplier_name, po_no, sku_code" } } 5. 函数可扩展:Hook + AOP + 扩展点 函数层聚焦“时机与顺序”的控制: 函数重写(Override):在不改主流程签名的情况下,替换实现。 Hook 机制(AOP 能力):在切面前/后/异常挂载逻辑,跨越模块复用。 扩展点机制 前置扩展点:在核心逻辑运行前拦截/补充数据。 后置扩展点:在核心逻辑完成后做派生动作(审计、通知等)。 覆盖扩展点:完全取代默认实现。 示例(TypeScript 伪代码) export const hooks = registerHooks('po')({ before('submit', async (ctx) => { await verifyBudget(ctx) }), after('submit', async (ctx, result) => { audit(ctx, result) }), override('calculateTax', async (ctx) => calcRegionalTax(ctx)) // 覆盖式扩展 }) 6. 应用生命周期扩展:模块的一等公民地位 针对“安装/升级/重启”等事件,模块可以声明自己的执行逻辑;针对“构建前/构建后、生命周期前/生命周期后”,平台提供钩子做元数据编排与系统级处理。 onInstall / onUpgrade / onRestart beforeBuild / afterBuild beforeLifecycle / afterLifecycle 元数据编排:将模型、视图、路由、动作、Hook 等产物做依赖拓扑排序,生成稳定装配序列(支持幂等与回滚)。 示例 export const lifecycle = { async onInstall(ctx) { await seedDicts(ctx) }, async onUpgrade(ctx) { await migrate('v2->v3', ctx) }, async beforeBuild(ctx) { validateMetadata(ctx.graph) }, async afterBuild(ctx) { warmupCaches() } } 7. 平台自身能力 SPI:内核也能被替换 当差异需要下沉到底座时,使用 SPI(Service Provider Interface): 网络协议层 SPI:自定义编解码/传输策略。 驱动层 SPI:接入自研/第三方驱动(消息、存储、设备)。 FaaS 层 SPI:执行约束 SPI(限流/超时/重试)与 RPC 调用 SPI。 持久层 SPI 与 ORM 层 SPI:数据源路由、审计字段、软删、分片等。 示例 export interface StorageSPI { put(object: Buffer, meta: Meta): Promise<URL> get(url: URL): Promise<Buffer> } @Spi('storage') export class MinIOStorage implements StorageSPI { /* ... */ } SPI 的价值在于:当“函数扩展不够用”时,仍可在标准接口之下替换底座实现,而无需修改上层业务代码。 8. 元数据编排:把碎片装配成系统 Oinone 将模型/视图/路由/动作/Hook/SPI等产物抽象为统一元数据,通过声明式依赖与编排规则完成构建与运行期装配: 依赖声明:dependsOn: [user, workflow@>=2.1] 装配顺序:order: [model, view, hook] 作用域/租户选择器:tenantSelector: ["region==EMEA"] 冲突解决:优先级、命名空间、策略(覆盖/合并/忽略) 可回滚:每一步装配都有幂等检查与反向操作 示例(module.yaml) name: po-approval version: 1.3.0 dependsOn: - user - workflow@>=2.1 order: [model, view, hook] guards: tenantSelector: ["region==EMEA"] 9. 典型落地场景 多业务线的差异表单 用“字段重写 + 视图替换”实现 B2B 与零售两套表单,同步复用校验 Hook。 合规化审计 在“后置扩展点”统一落审计日志,接入“持久层 SPI”发送到冷存。 跨地域税则 覆盖 calculateTax 函数,在租户维度启用差异化策略。 活动期临时字段 通过“临时继承”与“租户选择器”在活动期注入派生字段,活动结束即回收。 替换存储底座 基于 “StorageSPI” 从本地盘切换到对象存储,无需业务改动。 10. 工程化与治理 版本与灰度:模块语义化版本 + 兼容性检查;按租户/环境灰度装配。 隔离性:命名空间、权限最小化;动作与 Hook 执行的资源限额。 可观测性:对每个扩展点输出指标/日志/追踪,如 hook.duration、override.count。 安全:Hook 的输入输出做 Schema 校验;SPI 提供沙箱/白名单。 稳定性:扩展点默认要幂等;提供熔断/降级与开关管理。 开发体验:热重载、扩展点可视化、冲突检测与一键回滚。 11. 心智模型:三板斧 先装配,后编码:能用元数据/编排解决的,优先不用代码。 优先 Hook,慎用 Override:Hook 可叠加且更安全,Override 只在语义确实需要替换时使用。 API→SPI 的下沉路径:当应用层扩展不够用,再通过 SPI 下沉到底座。 Oinone 把“可扩展”做成了一套从 UI 到模型、从函数到生命周期、再到平台内核的完整方法论。通过 API 生命周期扩展 + 平台 SPI 扩展 两条通道,叠加 字段/函数重写、Hook/AOP、扩展点 与 主题/视图/路由/动作 等颗粒化插拔,既能支撑快速装配,又能承载深度定制。最终让开发者只写差异,让系统在复杂业务下稳定演进。