NocoBase 服务端插件(Server Plugin)开发指南:Plugin 基类、生命周期钩子与 this.app 应用上下文

发布时间:2026/9/17 4:54:01

NocoBase 服务端插件(Server Plugin)开发指南:Plugin 基类、生命周期钩子与 this.app 应用上下文 NocoBase 服务端插件Server Plugin开发指南Plugin 基类、生命周期钩子与 this.app 应用上下文【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobaseNocoBase 采用微内核 插件化架构服务端插件Server Plugin是扩展服务端能力注册接口、监听数据库事件、定义权限、调度任务等的主要方式。本文以服务端插件入口文件src/server/plugin.ts为中心系统讲解Plugin基类结构、afterAdd/beforeLoad/load/install等生命周期钩子的执行时机与源码级调度原理并结合this.app上挂载的 logger、db、resourceManager、acl、pm 等成员说明插件如何与系统各模块协作。读完本文你将能独立编写一个结构规范、生命周期调用正确的 NocoBase 服务端插件。服务端插件的定位与文件约定在 NocoBase 中服务端插件是扩展服务端功能的主要方式。插件包的src/server/目录下约定存放服务端代码其中src/server/plugin.ts或src/server/index.ts—— 插件入口导出继承自nocobase/server的Plugin子类src/server/collections/—— 数据表定义目录插件加载时会通过db.import()自动导入见 插件类源码 中的loadCollections()src/server/migrations/—— 数据迁移脚本目录升级时自动加载见loadMigrations()plugin.ts。关于插件骨架的完整目录结构可以参考 编写第一个插件其中src/server/plugin.ts正是本节所述服务端插件入口。插件类基础结构一个最基本的服务端插件类如下摘自 关联文档import { Plugin } from nocobase/server; export class PluginHelloServer extends Plugin { async afterAdd() {} async beforeLoad() {} async load() {} async install() {} async afterEnable() {} async afterDisable() {} async remove() {} async handleSyncMessage(message: Recordstring, any) {} static async staticImport() {} } export default PluginHelloServer;从源码看Plugin是一个抽象基类packages/core/server/src/plugin.ts#L44它实现了PluginInterface包含beforeLoad、load()、getName()并内置了app、options等字段export interface PluginInterface { beforeLoad?: () void; load(); getName(): string; } export abstract class PluginO any implements PluginInterface { options: any; app: Application; ... }所有生命周期方法在基类中都有空实现如afterAdd() {}、async load() {}子类只需按需覆写无需调用super。此外基类还提供了若干非空实现的辅助能力详见下文「插件类的隐藏能力」一节。插件实例由PluginManager统一创建new P(createAppProxy(this.app), options)plugin-manager.ts#L358构造时会将应用实例代理和插件元信息name、packageName、version、enabled、installed、isPreset等注入this.app与this.options这也是插件内部可以直接使用this.app和this.name的原因。生命周期方法详解插件的生命周期方法按固定顺序执行每个方法都有明确的执行时机与用途生命周期方法执行时机说明staticImport()插件加载前类的静态方法在跟应用或插件状态无关的初始化阶段执行用于不依赖插件实例的初始化工作。afterAdd()插件被添加到 PluginManager 后立即执行此时插件实例已创建但并非所有插件都已初始化完成可以做一些基础的初始化。beforeLoad()在所有插件的load()之前执行此时已经能拿到所有已启用的插件实例。适合注册数据库模型、监听数据库事件、注册中间件等准备工作。load()插件加载时执行所有插件的beforeLoad()执行完毕后才会开始执行load()。适合注册资源、API 接口等核心业务逻辑——比如通过resourceManager注册自定义 REST API。注意load()阶段数据库还没有完成同步不能执行数据库查询或写入操作——数据库操作应放在install()或请求处理函数中。install()插件首次激活时执行只在插件第一次被启用时执行一次通常用于初始化数据库表结构、插入初始数据等安装逻辑。如果后续版本需要变更表结构或迁移数据应该用 Migration 升级脚本 来处理。afterEnable()插件被启用后执行每次插件被启用时都会执行可以用来启动定时任务、建立连接等。afterDisable()插件被禁用后执行可以用来清理资源、停止任务、关闭连接等。remove()插件被删除时执行用于编写卸载逻辑比如删除数据库表、清理文件等。handleSyncMessage(message)多节点部署时的消息同步应用运行在多节点模式下时用于处理从其他节点同步过来的消息。staticImport()与应用状态无关的静态初始化staticImport()是Plugin类上的静态方法不依赖插件实例。NocoBase 通过runPluginStaticImports()packages/core/server/src/run-plugin-static-imports.ts#L13在应用启动早期扫描所有插件包逐个调用const plugin await importModule(packageName); if (plugin plugin.staticImport) { await plugin.staticImport(); }从源码结构看它适合做环境探测、全局配置注入等不依赖应用上下文的工作且单个插件的失败不会阻断其他插件catch后continue。afterAdd()加入 PluginManager 后立即触发在 PluginManager.addOrThrow() 中插件实例创建后会立刻执行await instance.afterAdd()。注意此时应用尚未进入加载流程其他插件可能还未初始化因此这里只能做插件自身的轻量准备。beforeLoad() 与 load()应用启动时的两阶段加载PluginManager.load()plugin-manager.ts#L428-L511将加载拆成两个循环第一轮遍历所有已启用插件依次执行plugin.beforeLoad()第二轮再次遍历依次执行plugin.loadCollections()→plugin.loadAI()→plugin.load()并将plugin.state.loaded置为true同时向外广播beforeLoadPlugin/afterLoadPlugin应用事件。这意味着beforeLoad()阶段你拿到的所有已启用插件实例都处于可用状态可以安全地在beforeLoad()里读取其他插件实例如this.app.pm.get(xxx)而load()则专注于注册资源、接口等业务逻辑。文档明确提示load()阶段数据库尚未同步不要在此阶段执行数据库查询或写入这类操作应放到install()或请求处理函数中。install()仅首次激活执行PluginManager.install()plugin-manager.ts#L513-L554在插件启用流程中先执行await this.app.db.sync()完成数据库同步再对未安装的插件执行plugin.install(options)随后标记installed true并广播beforeInstallPlugin/afterInstallPlugin事件。源码中InstallOptions支持cliArgs、clean、force、sync等选项plugin-manager.ts#L57-L62。因此install()是初始化表结构、插入种子数据的正确位置表结构或数据的后续演进则交由 Migration 数据迁移 处理。afterEnable() / afterDisable() / remove()在PluginManager.enable()plugin-manager.ts#L556-L688中启用插件的完整链路为beforeLoad() → loadCollections() → loadAI() → load() → beforeEnable() → db.sync() → install()未安装时→ afterEnable()其中afterEnable()每次启用都会触发适合启动定时任务、建立外部连接同时基类还预留了beforeEnable()、beforeDisable()、afterDisable()、beforeRemove()、afterRemove()等对称钩子plugin.ts#L127-L139。disable()流程会先广播beforeDisablePlugin事件并执行plugin.beforeDisable()再执行plugin.afterDisable()清理资源remove()则负责卸载逻辑如删除数据表、清理文件底层通过applicationPlugins仓库记录删除实现plugin-manager.ts#L737-L772。handleSyncMessage()多节点消息同步基类提供了成对的方法plugin.ts#L141-L152handleSyncMessage(message)—— 接收并处理其他节点同步过来的消息sendSyncMessage(message, options?)—— 通过this.app.syncMessageManager.publish(this.name, message, options)将消息发布给其他节点。只有应用以多节点模式运行时才需要关注这两个方法。执行顺序说明结合上文生命周期方法的典型执行流程如下静态初始化阶段staticImport()应用启动阶段afterAdd()→beforeLoad()→load()插件首次启用阶段afterAdd()→beforeLoad()→load()→install()插件二次启用阶段afterAdd()→beforeLoad()→load()插件禁用阶段禁用插件时执行afterDisable()插件删除阶段删除插件时执行remove()需要补充说明的是启用/禁用流程中的beforeEnable()/beforeDisable()分别先于afterEnable()/afterDisable()执行源码见 plugin-manager.ts#L630-L632 与 plugin-manager.ts#L704-L706且启用流程会在install()之前调用db.sync()这也是install()中能安全建表的原因。此外多插件启用时PluginManager会依据各插件package.json的peerDependencies做拓扑排序保证依赖插件先加载plugin-manager.ts#L1191-L1203。app 及相关成员插件扩展能力的核心入口在插件开发中通过this.app可以访问应用实例提供的各种 API——这是插件扩展功能的核心入口。app对象包含了系统的各个功能模块你可以在插件的生命周期方法中使用它们。app 成员列表成员名称类型/模块主要用途loggerLogger记录系统日志支持 info、warn、error、debug 等级别。详见 Logger 日志dbDatabaseORM 层操作、模型注册、事件监听、事务控制等。详见 Database 数据库resourceManagerResourceManager注册和管理 REST API 资源与操作处理器。详见 ResourceManager 资源管理aclACL定义权限、角色和资源访问策略。详见 ACL 权限控制cacheManagerCacheManager管理系统级缓存支持 Redis、内存缓存等多种后端。详见 Cache 缓存cronJobManagerCronJobManager注册和管理定时任务支持 Cron 表达式。详见 CronJobManager 定时任务i18nI18n多语言翻译和本地化。详见 I18n 国际化cliCLI注册自定义命令扩展 NocoBase CLI。详见 Command 命令行dataSourceManagerDataSourceManager管理多个数据源实例及其连接。详见 DataSourceManager 数据源管理pmPluginManager动态加载、启用、禁用、删除插件管理插件间的依赖关系。:::tip 提示各个模块的详细用法请参考对应的文档章节。:::源码视角基类内置的快捷成员Plugin基类实际上已经为最常用的几个成员提供了只读 getterplugin.ts#L68-L109插件内可以直接使用而无需经this.app中转this.db—— 等价于this.app.db数据库访问入口this.pm—— 等价于this.app.pm插件管理器this.ai—— 等价于this.app.aiManagerAI 能力入口this.log—— 基于应用 logger 按当前插件名module: this.name派生的子 logger日志会自动带上插件标识this.name/this.enabled/this.installed/this.isPreset—— 分别对应插件名、启用状态、安装状态、是否预置。同时基类还提供createLogger(options)用于创建独立命名的 loggerplugin.ts#L115-L117以及t(key, options)方法它会以插件的packageName作为命名空间调用app.i18n.t便于插件做多语言文案plugin.ts#L272-L274。插件类的隐藏能力约定优于配置的自动加载除了生命周期钩子Plugin基类还内置了几个自动化能力理解它们能帮你写出更精简的插件loadCollections()plugin.ts#L196-L209插件加载时自动扫描server/collections目录通过this.db.import({ directory, from: packageName })导入数据表定义。也就是说用文件方式定义的数据表无需在代码里手动注册。loadMigrations()plugin.ts#L169-L183自动扫描server/migrations目录按beforeLoad/afterSync/afterLoad三个批次交给PluginManager汇总执行见 loadPresetMigrations 与 loadOtherMigrations。loadAI()plugin.ts#L214-L263自动扫描插件内的ai/目录加载 AI Tools、MCP Server、Skills 与 AI Employees——NocoBase 作为 AI 无代码平台插件可以直接通过目录约定暴露 AI 能力。upgrade()升级时执行与install()配合完成版本演进install()只做首次安装之后的表结构/数据变更请走 Migration 数据迁移。这些方法的典型调用时机可从 PluginManager.load() 中看到每个插件在load()前都会先执行loadCollections()与loadAI()。小结与进一步阅读服务端插件开发的核心可以概括为三件事在src/server/plugin.ts中继承nocobase/server的Plugin基类覆写生命周期钩子遵循各钩子的执行时机静态初始化用staticImport()加载阶段用beforeLoad()/load()数据初始化用install()启停清理用afterEnable()/afterDisable()卸载用remove()通过this.app或基类快捷成员this.db、this.pm、this.log等与系统各模块协作并在load()阶段完成资源、接口、权限的注册。建议进一步阅读以下文档继续深入服务端开发概述 — 服务端各模块的总览和导航Collections 数据表 — 用代码定义或扩展数据表结构Database 数据库 — CRUD、Repository、事务与数据库事件Migration 数据迁移 — 插件升级时的数据迁移脚本Event 事件 — 应用级和数据库级的事件监听与处理ResourceManager 资源管理 — 注册自定义 REST API 和操作编写第一个插件 — 从零开始创建一个完整的插件Logger 日志 — 记录系统日志ACL 权限控制 — 定义权限和访问策略Cache 缓存 — 管理系统级缓存CronJobManager 定时任务 — 注册和管理定时任务I18n 国际化 — 多语言翻译Command 命令行 — 注册自定义 CLI 命令DataSourceManager 数据源管理 — 管理多个数据源【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/17 4:54:01

SQL Server PIVOT实战:从静态到动态行转列与性能调优

简介:围绕 SQL Server 中行转列 PIVOT 操作符的实战讲解,面向数据库开发、报表制作及数据分析人员,解决将行数据转为列展示的常见需求,尤其适合需要快速生成横向周报/月报的读者。内容从店铺一周收入表(WEEK_INCOME&am…

2026/9/17 4:54:01

C++17并行算法实战:STL中的执行策略与性能优化

如果有人搜“STL”出来一堆“STL转STP”“Revit导出STL”的内容,那多半是3D打印那边的STL文件格式,跟C开发者说的STL完全是两码事。这篇聊的是C标准模板库里的并行算法,也就是C17开始正式进入标准的那套std::execution策略、并行版本的std::s…

2026/9/17 4:49:01

Simulink悬架仿真建模实战:从1/4车模型到天棚阻尼控制

搞悬架仿真的朋友应该都有这种感觉:查资料的时候发现满屏都是论文里的公式推导,真要上手在Simulink里搭一个能跑的模型,反而找不到一份能把来龙去脉讲清楚的实操参考。这篇内容就是奔着解决这个问题来的,我从零开始搭过好几版悬架…

2026/9/17 5:44:03

Rocky Linux中文乱码解决:字体安装与locale/编码排查指南

刚把一台 Rocky Linux 9 的测试服务器部署好,网页一打开,满屏的“□□□□□□”,日志文件里全是“????”。这种中文乱码,很多人第一反应是去改 locale、加export LANGzh_CN.UTF-8,结果折腾半天还是老样子。其实在…

2026/9/17 5:44:03

Fabric自动化部署工具:原理、实践与性能优化

1. 为什么需要自动化部署工具每次手动登录服务器敲命令部署代码的日子该结束了。记得刚入行那会儿,我负责维护三个测试环境,每次发版都要重复执行十几条命令,稍不留神就会漏掉某个步骤。最惨的一次是把数据库迁移脚本漏了,导致线上…

2026/9/17 5:44:03

PC端CAN通信工程实践:USB-CAN上位机系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/17 5:44:03

WSL下Node开发环境完整搭建指南:从安装到踩坑修复

把Windows下的Node项目迁进WSL,一开始只是因为node-sass编译老挂、路径分隔符恶心。真正动手装的时候才发现,WSL本身的门槛也不低:下载卡住、403、版本太旧、装完Node又冒出一堆npm权限和模块导出的报错。这篇文章把我在WSL里安装Node的完整踩…

2026/9/17 5:39:03

EVTOL无人机AI图像处理:从端边云架构到模型部署的完整链路

简介:这是一份围绕EVTOL低空经济无人机AI图像处理系统建设的完整方案PPT,适合无人机系统设计、AI算法研发及低空经济应用规划人员参考,覆盖从总体架构到实施落地的全流程。资源共1个文件,为PPT演示文稿,容量约1.04MB&a…

2026/9/16 12:52:37

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/17 0:03:13

WiFi密码安全测试:从原理到实战的字典暴力破解指南

1. 写在前面:我为什么要研究WiFi密码这件事先交代一下背景。我身边有不少朋友,家里的WiFi密码常年是"12345678"或者"88888888",问就是"好记"。直到有一次,隔壁邻居蹭网蹭到我家路由器后台都进不去&…

2026/9/17 0:03:13

redis-py服务控制与监控函数实战:从ping到slowlog的巡检指南

我用 redis-py 写了快五年的业务代码,坦白说,真正让我觉得这个客户端“像一个成熟工具箱”的,不是 get/set 那套基本操作,而是它那批专门做服务控制与状态监控的辅助函数。日常开发里,大家把redis.Redis(host..., deco…

2026/9/17 0:03:13

SpringBoot+Vue3实现中小企业设备管理系统开发实践

1. 项目概述与核心价值中小企业设备管理系统是制造业、服务业等领域的基础信息化工具。传统设备管理往往依赖Excel表格或纸质记录,存在数据孤岛、流程混乱、维护成本高等痛点。这套基于Java SpringBootVue3MyBatis的技术方案,通过前后端分离架构实现了设…

2026/9/16 22:55:57

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/16 22:56:09

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/16 22:56:16

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码