从插件系统到微内核平台:一篇从入门到进阶的 NocoBase 架构笔记

Jiayu Xu Lv2

如果你第一次听到“微内核架构”,可以先把它理解成一句话:

1
核心系统只保留最稳定、最通用的能力,具体业务能力都通过插件接进来。

这和我们平时用的很多软件很像。

浏览器本身只提供浏览网页、管理标签页、运行扩展的基础能力。广告拦截、翻译、密码管理、截图工具,都是扩展插件提供的。

VS Code 本身是一个编辑器内核。Python、Go、Java、Markdown、GitLens、Docker、数据库管理,这些能力大多来自插件。

平台型后端也可以用类似思路设计。核心不直接写死 CRM、审批、报表、文件、工作流、AI 调用,而是提供一套稳定的注册和运行机制,让这些能力以插件形式接入。

NocoBase 是一个很好的参考对象。它采用微内核架构,核心负责插件生命周期、依赖管理和基础能力封装,业务功能由插件提供。服务端插件可以注册数据表、资源接口、权限、事件、定时任务、日志、Telemetry 和迁移;客户端插件可以注册路由、页面、区块、字段和按钮。

本文不是复刻 NocoBase 源码,也不是贴一大段 Python 教学代码,而是把它背后的架构思路讲成一个从入门到进阶的路径。

读完这篇,你应该能回答三个问题:

1
2
3
1. 插件系统和微内核到底解决什么问题?
2. 为什么一个平台不能只有 PluginManager?
3. 从入门 demo 到生产平台,中间还差哪些工程能力?

先看问题

假设我们一开始写的是一个普通业务系统。需求来了,我们就在代码里加功能:

1
2
3
4
5
6
7
8
新增客户表
新增订单表
新增订单接口
新增订单页面
新增审批逻辑
新增导出按钮
新增权限判断
新增定时任务

早期这样写没有问题,因为系统小,业务也清楚。

但当它变成一个平台以后,情况会变复杂:

1
2
3
4
5
6
7
客户模块可能要被替换;
订单模块可能由不同团队维护;
审批、通知、导入导出希望复用给不同业务;
每个租户可能启用不同功能;
有些功能需要单独安装、禁用、升级;
前端页面、表单、字段和按钮也要能扩展;
权限、审计、日志、指标不能每个模块各写一套。

这时继续往核心系统里塞业务代码,核心会越来越大,也越来越难改。

微内核架构的目标就是把这个问题反过来:

1
2
3
核心不要知道太多业务。
核心只提供规则和注册点。
业务能力通过插件注册进来。

所以,微内核不是为了“少写代码”,而是为了让系统长期演进时不失控。

入门:最小插件系统长什么样

最小的插件系统可以很简单:

1
2
3
4
Kernel
├─ PluginManager
├─ HookBus
└─ ServiceRegistry

其中:

1
2
3
PluginManager  负责加载、启用、禁用插件
HookBus 负责让插件监听某些事件
ServiceRegistry 负责让插件注册可调用能力

一个非常简化的插件可能长这样:

1
2
3
4
5
6
7
8
class ArticlePlugin:
name = "article"

def load(self, app):
app.services.register("article.publish", self.publish)

def publish(self, article_id):
...

应用启动时:

1
2
app.plugins.add(ArticlePlugin())
app.plugins.enable_all()

这已经具备插件系统的雏形:

1
2
3
核心不直接写 article.publish;
ArticlePlugin 自己把 publish 能力注册进系统;
其他地方通过 service registry 调用它。

这一步适合入门理解,但还不是完整平台。

入门:为什么只有 PluginManager 不够

如果插件只负责注册几个函数,PluginManager 就够了。

但真实平台里的插件通常要做更多事情:

1
2
3
4
5
6
7
8
9
10
11
定义数据表;
扩展已有数据表;
注册 API;
配置权限;
监听数据变化;
注册后台任务;
注册前端页面;
注册表单字段;
保存插件配置;
升级数据库结构;
输出日志、指标和 trace。

如果没有统一机制,每个插件就会自己想办法:

1
2
3
4
5
6
插件 A 自己建表;
插件 B 自己写路由;
插件 C 自己判断权限;
插件 D 自己开线程跑定时任务;
插件 E 自己写日志格式;
插件 F 自己处理升级脚本。

最后的问题是:核心看起来变小了,但系统并没有变简单,只是复杂度被分散到了插件里。

完整微内核需要的不只是“能加载插件”,而是“所有重要能力都有受控入口”。

进阶:平台需要哪些注册表

可以把一个平台内核想象成一组注册表。

插件不能随便改系统内部状态,而是通过这些注册表把能力挂进来。

注册表 解决的问题 插件通常注册什么
PluginManager 插件怎么加载、排序、启停 插件本身、依赖关系、生命周期
CollectionManager 数据模型怎么扩展 表、字段、关联、默认值、校验
ResourceManager API 能力怎么暴露 resource:action、CRUD、自定义操作
ACL 权限怎么统一判断 角色权限、公开接口、数据范围
EventBus 副作用怎么解耦 事件监听器、数据变化监听器
CronJobManager 后台任务怎么托管 定时任务、清理任务、同步任务
FrontendRegistry 前端怎么扩展 路由、页面、区块、字段、按钮
MigrationManager 版本升级怎么处理 表结构变更、数据迁移、配置迁移
Logger / Telemetry 插件怎么被观测 日志、指标、链路追踪

这张表是理解微内核平台的关键。

一个插件不应该只是“一段被 import 的代码”。它更像一个完整扩展包:

1
Plugin = 后端能力 + 前端能力 + 数据模型 + 权限 + 配置 + 生命周期 + 迁移

NocoBase 的插件体系就是这个方向:不是只做后端模块,而是把服务端和客户端能力都纳入插件化运行时。

进阶:一条请求如何串起来

先看一个具体例子。

假设有一个 ArticlePlugin,它提供文章管理能力。它做了几件事:

1
2
3
4
5
1. 注册 articles 数据模型
2. 注册 articles 的 CRUD 操作
3. 注册 articles:publish 自定义操作
4. 配置谁可以发布文章
5. 发布后触发审计和搜索索引更新

用户点击“发布文章”按钮后,请求可能是:

1
/api/articles:publish

它在平台里的路径是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
前端按钮

调用 /api/articles:publish

ResourceManager 解析 resource=articles, action=publish

ACL 判断当前用户能不能执行 articles:publish

ArticlePlugin.publish 执行业务逻辑

Database 更新文章状态

EventBus 发出 articles.updated 事件

AuditPlugin 记录审计

SearchPlugin 刷新索引

Telemetry 记录耗时、成功次数、trace

返回结果

这条链路里,文章业务只是一个插件。权限、事件、审计、指标、错误处理都不应该散落在 ArticlePlugin 里,而应该经过平台统一入口。

这就是微内核平台和普通业务系统的差别。

普通业务系统关心:

1
怎么写一个发布文章接口?

平台系统关心:

1
2
3
4
5
插件如何声明 articles:publish?
这个 action 如何统一进入权限、日志、审计和指标?
其他插件如何观察这次发布?
禁用插件时这些注册项如何撤销?
升级插件时数据结构如何迁移?

问题一变,架构就变了。

进阶:Collection 先行

平台型系统里,数据模型应该先于页面和接口。

NocoBase 里有一个核心概念叫 Collection。你可以把它理解成“带元信息的数据表定义”。

它不只是表名,还包括:

1
2
3
4
5
6
7
8
字段名
字段类型
显示标题
默认值
是否必填
验证规则
关联关系
前端控件建议

比如文章插件可以定义:

1
2
3
4
5
6
7
8
9
app.collections.define(
name="articles",
title="Articles",
fields=[
Field("title", "string", required=True),
Field("content", "text"),
Field("status", "string", default="draft"),
],
)

这个定义不是只给数据库看的。它后面还可以推导出很多东西:

1
2
3
4
5
6
7
8
CRUD API
列表字段
表单字段
权限资源
审计对象
导入导出格式
搜索索引
工作流触发条件

很多系统会反过来做:

1
2
3
4
先写页面;
再补接口;
再补权限;
最后发现数据结构不够用。

平台系统更稳的顺序是:

1
2
3
4
先定义 Collection
再生成或注册 Resource
再绑定 ACL
最后让前端围绕 Collection 和 Resource 生成页面、表单和操作

这就是“数据模型驱动”。

如果平台支持动态建模,还要注意 SQL 安全。值可以参数绑定,但表名、字段名不能作为普通参数传入,必须白名单校验:

1
2
3
4
5
6
IDENT_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")

def safe_ident(name: str) -> str:
if not IDENT_RE.match(name):
raise ValueError(f"unsafe SQL identifier: {name!r}")
return name

动态建模越强,越要把字段名、排序、过滤、关联查询这些边界做清楚。

进阶:Resource Action 统一 API

如果每个插件都随便写路由,系统很快会变乱:

1
2
3
4
/api/article/create
/api/post/update
/api/v1/content/remove
/api/custom/publish

命名不统一,权限不统一,审计不统一,日志和指标也不统一。

NocoBase 风格的 ResourceManager 更推荐把能力抽象成:

1
resource:action

例如:

1
2
3
4
5
6
7
8
9
articles:list
articles:get
articles:create
articles:update
articles:destroy
articles:publish
orders:salesByStatus
approval:submit
app:getInfo

这样 CRUD、图表聚合、审批提交、文件上传、导入导出,本质上都可以走同一种调用协议。

插件注册自定义 action:

1
2
3
4
5
app.resources.register_action(
"articles",
"publish",
publish_article,
)

调用时:

1
app.resources.call(ctx, "articles:publish", id=1)

ResourceManager 负责统一做这些事:

1
2
3
4
5
6
7
解析 resource/action
检查 ACL
注入用户上下文和数据范围
找到默认 CRUD 或自定义 handler
记录日志和指标
触发 before/after 事件
包装响应和错误

这就是平台化的价值。业务插件只关心“我要提供什么 action”,治理逻辑由统一入口处理。

进阶:ACL 不只是隐藏按钮

很多系统把权限理解成“前端按钮显不显示”。

这只是体验,不是安全。

真正的权限必须在后端统一执行,而且最好能进入查询层。

最基本的权限可以这样描述:

1
2
3
app.acl.grant("admin", "articles", "*")
app.acl.allow("articles", "list", "logged_in")
app.acl.allow("articles", "get", "logged_in")

含义是:

1
2
3
admin 可以操作 articles 的全部 action;
登录用户可以查看文章列表和详情;
其他操作默认不允许。

ResourceManager 在执行 action 前统一检查:

1
2
if not app.acl.can(ctx, resource, action):
raise PermissionError(...)

进阶一点,还要支持数据范围。

比如销售只能看自己的订单:

1
2
3
orders:list
role = sales
data_scope = owner_id = current_user.id

请求链路应该是:

1
2
3
4
5
6
7
8
9
ResourceManager

ACL 检查通过

注入 data_scope

CollectionManager 合并 filter

生成带 WHERE 的查询

所以权限不应该散落在每个业务函数里,也不应该只停留在 UI 层。它应该绑定到 resource:action,并在统一入口执行。

进阶:事件用于解耦副作用

事件适合处理副作用。

比如:

1
2
3
4
5
6
7
记录审计日志
发送通知
刷新缓存
同步搜索索引
触发工作流
上报指标
同步外部系统

文章发布时,ArticlePlugin 不应该手动调用所有插件:

1
2
3
4
audit.record(...)
search.reindex(...)
notify.send(...)
workflow.trigger(...)

这样会让 ArticlePlugin 知道太多其他插件。

更好的方式是发事件:

1
app.events.emit("articles.published", article=article)

其他插件自己监听:

1
2
3
app.events.on("articles.published", audit_listener)
app.events.on("articles.published", search_listener)
app.events.on("articles.published", notification_listener)

事件通常分两类:

1
2
app.events    应用级事件:启动、停止、插件加载、资源调用
db.events 数据库级事件:创建、更新、删除、模型定义

事件适合副作用,但不适合承载主流程里的强依赖逻辑。

如果“发布文章必须先扣库存”这种逻辑是主流程的一部分,就应该显式调用,不应该藏在事件监听器里。事件监听器失败以后要不要回滚主流程,也必须提前定义清楚。

生产系统里,事件监听还要能注销:

1
2
handle = app.events.on("articles.published", listener)
handle.close()

否则插件禁用以后监听器还在运行,就是资源泄漏。

进阶:后台任务要由内核托管

插件不要自己偷偷开线程、定时器或消费者。

错误示例:

1
threading.Thread(target=self.loop).start()

这样做的问题是:

1
2
3
4
5
6
内核不知道任务存在;
禁用插件时停不掉;
异常没人收集;
日志和指标没有统一记录;
多实例部署时可能重复执行;
资源泄漏难排查。

更好的方式是通过 CronJobManager:

1
2
3
4
5
app.cron.add_job(
name="article.daily_report",
cron="0 0 * * *",
handler=daily_report,
)

禁用插件时:

1
app.cron.remove_job("article.daily_report")

生产里的任务管理还要考虑:

1
2
3
4
5
6
7
8
分布式锁
任务超时
失败重试
任务日志
任务指标
并发控制
禁用开关
补偿策略

任务托管的核心不是“帮你跑 cron”,而是让后台行为纳入平台治理。

进阶:前端也要插件化

很多团队一开始只做后端插件。后来发现菜单、页面、字段、表单、按钮、设置页也都要扩展,于是前端到处打补丁。

平台系统更合理的设计是:插件是全栈扩展单元。

1
Plugin = Backend Extension + Frontend Extension + Metadata + Lifecycle + Permissions + Configuration

后端插件注册:

1
2
3
4
5
6
数据模型
资源操作
权限
事件
任务
迁移

前端插件注册:

1
2
3
4
5
6
7
路由
菜单
页面
区块
字段控件
操作按钮
设置页面

一个插件目录可以长这样:

1
2
3
4
5
6
7
8
9
10
11
12
article-plugin/
├─ plugin.json
├─ server/
│ ├─ plugin.py
│ ├─ collections.py
│ ├─ resources.py
│ └─ migrations/
└─ client/
├─ routes.tsx
├─ blocks.tsx
├─ fields.tsx
└─ settings.tsx

这样,ArticlePlugin 不只是“后端多一个接口”,而是可以完整带来文章表、文章接口、文章权限、文章页面、文章表单、文章按钮和文章设置页。

这才是平台插件。

高阶:生命周期不能太粗

入门版插件系统可能只有:

1
2
activate()
deactivate()

真实平台不够用。

参考 NocoBase 的插件生命周期,一个更完整的拆分是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static_import

after_add

before_load

load

install 只在首次启用时执行

after_enable

running

after_disable

remove

可以用更通俗的话理解:

阶段 什么时候发生 适合做什么
static_import 类级初始化 注册全局类型、加载静态描述
after_add 插件加入管理器后 准备轻量状态、读取基本配置
before_load 所有插件 load 前 定义 Collection、注册中间件、监听事件
load 插件加载时 注册资源、API、权限、前端扩展
install 第一次启用时 初始化数据、默认配置、默认权限
after_enable 每次启用后 启动任务、建立连接、预热缓存
after_disable 禁用时 停止任务、关闭连接、注销监听
remove 删除时 清理插件私有资源

这里最容易混淆的是 install 和 migration。

install() 只处理首次启用。插件升级以后要改表结构、修数据、补配置,应该走 MigrationManager,而不是重复执行 install。

另一个关键点是 before_loadload 的分工。

通常:

1
2
before_load 先注册模型和底层准备工作
load 再注册 API、权限、页面、任务等能力

这样可以减少“插件 A 的 API 依赖插件 B 的 Collection,但 B 还没注册”的问题。

高阶:四个平面看平台内核

到这里,我们可以把微内核平台分成四个平面。

第一是 Runtime Plane,负责插件怎么运行:

1
2
3
4
5
PluginManager
DependencyResolver
LifecycleRunner
PluginStateStore
PackageManager

它处理插件发现、依赖排序、启用、禁用、卸载、状态持久化和版本约束。

第二是 Extension Plane,负责插件怎么提供业务能力:

1
2
3
4
5
6
CollectionManager
ResourceManager
ServiceRegistry
EventBus
WorkflowEngine
FrontendRegistry

它决定插件可以向系统注册哪些能力。

第三是 Governance Plane,负责插件怎么被治理:

1
2
3
4
5
6
7
ACL
Logger
Telemetry
Audit
RateLimiter
CircuitBreaker
HealthCheck

插件越多,治理越重要。没有统一治理面,平台只能依赖插件自觉。

第四是 Configuration Plane,负责插件配置、开关、密钥和升级:

1
2
3
4
5
ConfigManager
FeatureFlag
SecretManager
VersionManager
MigrationManager

这四个平面合起来,才是平台内核,而不是一个孤立的 PluginManager

高阶:日志和 Telemetry 是一等公民

平台内核不能只关心插件怎么运行,还要关心插件怎么被观察。

日志至少要带上:

1
2
3
4
5
6
7
8
plugin_name
resource
action
user_id
request_id
trace_id
duration
error_type

指标至少应该覆盖:

1
2
3
4
5
6
7
8
9
10
plugin_enable_total
plugin_enable_failed_total
plugin_load_duration_seconds
resource_call_total
resource_call_failed_total
resource_call_duration_seconds
cron_job_run_total
cron_job_failed_total
db_operation_total
db_operation_duration_seconds

Trace 解决的是链路问题。一次请求可能经过:

1
2
3
4
5
6
7
8
API request
-> ResourceManager
-> ACL
-> ArticlePlugin.publish
-> Database.update
-> db.after_update event
-> AuditPlugin
-> SearchIndexPlugin

没有 trace_id,这些日志会散在各处。

NocoBase 的 Telemetry 模块基于 OpenTelemetry 思路提供 Trace 和 Metric 能力。自己实现平台时,即使先做简化版,也应该优先覆盖这些统一入口:

1
2
3
4
5
ResourceManager
PluginManager
CollectionManager / Database
CronJobManager
EventBus

因为统一入口观测一次,比每个插件各写一遍更可靠。

高阶:从教学版到生产版还差什么

如果只是学习,一个 Python demo 可以很小:

1
2
3
4
5
6
7
Application
PluginManager
CollectionManager
ResourceManager
ACL
EventBus
CronJobManager

这足够讲清楚概念。

但生产系统还要补很多工程能力。

第一,插件 manifest。

插件元信息不要只写在类里,应该有独立描述:

1
2
3
4
5
6
7
8
9
10
11
name: article
version: 1.0.0
apiVersion: 1
dependencies:
- audit >= 1.0.0
server: article_plugin.server:ArticlePlugin
client: article_plugin.client:index.js
permissions:
- articles:list
- articles:create
- articles:publish

第二,插件发现机制。

教学版可以手动注册:

1
app.pm.add(ArticlePlugin)

生产版要支持本地插件目录、包管理、远程插件市场或语言生态里的 entry points。

第三,版本约束。

依赖不只是插件名,还包括插件版本、内核 API 版本、语言版本、数据库版本和前端运行时版本。

第四,MigrationManager。

字段新增、字段重命名、类型变更、索引调整、配置迁移、数据补偿都应该走 migration,并记录每个插件每个 migration 是否执行过。

第五,事务边界。

文章发布成功后刷新搜索索引失败,要不要回滚发布状态?订单创建后工作流失败,要不要回滚订单?通知失败是否影响主流程?这些不能靠事件机制自动回答,必须由平台语义定义。

第六,禁用和删除。

禁用插件时要撤销事件监听、中间件、缓存、连接、消费者、定时任务、前端路由、权限片段和临时资源。删除插件时是否删除用户数据,更要谨慎。

第七,第三方插件隔离。

如果插件来自第三方或不可信,不建议直接运行在同一个进程里。进程内插件很难安全限制文件访问、网络访问、CPU、内存和死循环。更稳妥的是独立进程、容器、Worker Sandbox、HTTP/gRPC/IPC 调用、资源配额和签名校验。

第八,完整可观测性。

生产版应该把 Trace、Metric、Span、Exporter 和 Context propagation 做完整,至少覆盖资源调用、数据库操作、插件生命周期和后台任务。

常见误区

第一个误区是把插件系统等同于动态 import。

1
插件系统 = importlib.import_module(plugin_name)

这只是加载方式,不是架构。真正的插件系统必须有协议、生命周期、依赖管理、能力注册、权限控制、错误治理、日志监控和资源清理。

第二个误区是 Kernel 写太多业务逻辑。

如果 Kernel 里出现很多业务方法,边界通常已经坏了:

1
2
3
4
5
class Kernel:
def create_article(self): ...
def publish_article(self): ...
def export_excel(self): ...
def send_notification(self): ...

这些应该属于插件,而不是核心。

第三个误区是所有扩展都用 Hook。

Hook 适合事件通知,不适合表达所有扩展。

场景 推荐机制
多个插件监听某个事件 Event / Hook
插件提供一个可调用能力 Service / Resource
插件注册 API 操作 ResourceManager
插件定义数据结构 CollectionManager
插件控制权限 ACL
插件做后台任务 CronJobManager

第四个误区是权限散落在业务代码里。

权限应该统一挂在 resource:action 上,并进入后端查询层。

第五个误区是插件自己开线程、开消费者、开定时器。

后台任务必须由内核托管。

第六个误区是混用 install 和 migration。

首次安装和版本升级是两件事。

第七个误区是禁用插件但不清理资源。

插件禁用后还在监听事件、还在跑任务、还占用连接,就是资源泄漏。

从入门到进阶的落地路径

如果你想自己实现一个学习版,可以按四步走。

第一步,只做插件加载。

目标是理解:

1
2
3
4
什么是 Kernel
什么是 Plugin
什么是生命周期
插件如何注册一个函数

这一步可以只有:

1
2
3
4
Application
Plugin
PluginManager
ServiceRegistry

第二步,引入数据和 API 注册。

目标是理解:

1
2
3
4
插件如何定义 Collection
Collection 如何生成 CRUD
ResourceManager 如何统一分发 resource:action
ACL 如何统一拦截

这一步可以加入:

1
2
3
CollectionManager
ResourceManager
ACL

第三步,引入事件、任务和观测。

目标是理解:

1
2
3
主流程和副作用如何拆开
后台任务为什么要托管
日志、指标、trace 为什么要在统一入口做

这一步加入:

1
2
3
4
EventBus
CronJobManager
Logger
Telemetry

第四步,走向平台化。

目标是理解:

1
2
3
4
5
前端如何插件化
插件如何声明 manifest
版本升级如何 migration
插件禁用如何清理资源
第三方插件如何隔离

这一步加入:

1
2
3
4
5
FrontendRegistry
MigrationManager
ConfigManager
PluginManifest
Sandbox / Worker

不要一上来就写完整平台。先把核心链路跑通,再逐步补治理能力。

架构检查清单

设计自己的微内核平台时,可以用下面这份清单自检。

Kernel 边界:

1
2
3
4
[ ] Kernel 是否只保留稳定机制?
[ ] 业务能力是否都通过插件提供?
[ ] 插件是否不能随意修改内核内部状态?
[ ] 是否有清晰的 PluginContext 或受控 app API?

插件生命周期:

1
2
3
4
5
[ ] 是否区分首次安装和每次启用?
[ ] 是否有 before_load/load 阶段?
[ ] 是否有 after_disable 清理阶段?
[ ] 是否有 remove 删除阶段?
[ ] 是否有插件状态持久化?

数据模型:

1
2
3
4
[ ] 插件是否可以定义 Collection?
[ ] 插件是否可以扩展已有 Collection?
[ ] Collection 是否能推导出 Resource?
[ ] 数据迁移是否独立于 install?

API 与权限:

1
2
3
4
5
[ ] API 是否统一进入 ResourceManager?
[ ] 是否使用 resource/action 描述操作?
[ ] ACL 是否在统一入口执行?
[ ] 数据范围权限是否进入查询层?
[ ] 前端按钮是否能复用同一套权限语义?

事件与任务:

1
2
3
4
5
[ ] 是否有应用级事件?
[ ] 是否有数据库级事件?
[ ] 事件监听是否可注销?
[ ] 后台任务是否由内核托管?
[ ] 插件禁用时任务是否停止?

可观测性:

1
2
3
4
5
[ ] 插件生命周期是否有日志?
[ ] Resource 调用是否有日志和指标?
[ ] DB 操作是否有事件或指标?
[ ] CronJob 是否有运行日志和失败统计?
[ ] 是否有 trace_id 串联链路?

安全:

1
2
3
4
5
[ ] 第三方插件是否隔离运行?
[ ] 插件是否有权限声明?
[ ] 敏感配置是否通过 SecretManager 管理?
[ ] 插件包是否校验签名?
[ ] 插件是否不能直接访问全局配置?

总结

入门看,微内核就是:

1
核心少写业务,业务通过插件接入。

进阶看,微内核平台不是只有 PluginManager,而是一组稳定注册表:

1
2
3
4
5
6
7
8
9
PluginManager
CollectionManager
ResourceManager
ACL
EventBus
CronJobManager
FrontendRegistry
MigrationManager
Logger / Telemetry

高阶看,微内核真正解决的是长期演进问题:

1
2
3
4
5
6
7
8
插件如何安装、启用、禁用、删除;
数据如何迁移;
权限如何统一;
任务如何托管;
副作用如何解耦;
前端如何扩展;
日志、指标和 trace 如何贯穿全链路;
第三方插件如何隔离。

从 NocoBase 可以学到的核心不是某个具体 API,而是一套平台化纪律:

1
2
3
4
5
6
7
8
9
10
核心保持小而稳定;
业务能力全部插件化;
插件通过生命周期进入系统;
数据模型先行;
API 通过 resource/action 统一管理;
权限绑定资源操作;
事件处理副作用;
任务由内核托管;
前后端都应该插件化;
升级、禁用、观测和安全都要被治理。

所以,微内核不是插件加载器。

它更像一个平台操作系统:核心负责提供稳定规则,插件负责带来变化。规则越清晰,平台越能在长期演进中保持可控。

参考资料

  • 标题: 从插件系统到微内核平台:一篇从入门到进阶的 NocoBase 架构笔记
  • 作者: Jiayu Xu
  • 创建于 : 2026-05-20 16:00:13
  • 更新于 : 2026-05-20 16:10:45
  • 链接: https://www.rasior.com/2026/05/20/20260520_microkernel-platform-architecture/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。