Nacos 的 SPI 扩展点有 12 个,你只需要知道这 5 个:插件机制从原理到优先级排序

发布时间:2026/7/11 20:43:32

Nacos 的 SPI 扩展点有 12 个,你只需要知道这 5 个:插件机制从原理到优先级排序
Nacos 的 SPI 扩展点有 12 个你只需要知道这 5 个插件机制从原理到优先级排序文章目录Nacos 的 SPI 扩展点有 12 个你只需要知道这 5 个插件机制从原理到优先级排序你想改 Nacos 的行为不用改它的代码Java SPI vs Nacos SPIJava SPI 的工作方式Nacos SPI 的工作方式扩展点加载流程源码走读NacosServiceLoader 的核心方法加载时序排序机制order 值怎么确定Nacos 的 12 个扩展点你只需要知道这 5 个扩展点的插件目录一张图带走Nacos SPI 加载全流程不适用本文描述的情况你想改 Nacos 的行为不用改它的代码去年有个客户要在 Nacos 里接 LDAP 认证。团队里有人第一反应是 fork 一份 Nacos 源码改掉认证逻辑然后自己编译一个版本。不用。Nacos 从 1.4.0 开始引入 SPI 插件机制。认证、健康检查、数据源、配置变更通知——这些核心功能都有扩展点。你只需要写一个实现类打个 jar 包放到 Nacos 的 plugins 目录下。Nacos 的 SPI 机制和 JDK 原生的 SPI 不一样。JDK SPI 用ServiceLoader加载所有实现类都会被实例化不能排序、不能按条件加载。Nacos 自己实现了一套NacosServiceLoader支持优先级排序、条件过滤、单例管理。这篇文章拆开 Nacos SPI 的加载流程源码搞清楚它和 Java SPI 的区别、扩展点的优先级怎么排、你写插件时需要知道的最小接口集合。⚠️ 本文基于 Nacos Server 2.3.x。SPI 插件机制从 1.4.0 开始引入2.0.0 后扩展了鉴权插件和数据源插件接口。如果你用的是 1.4.x可用的扩展点比 2.x 少。Java SPI vs Nacos SPIJava SPI 的工作方式// 接口publicinterfacePayment{voidpay();}// 实现类publicclassAlipayPaymentimplementsPayment{...}// 配置文件META-INF/services/com.example.Paymentcom.example.AlipayPayment// 加载ServiceLoaderPaymentloaderServiceLoader.load(Payment.class);for(Paymentp:loader){p.pay();// 所有实现类都会被实例化和遍历}Java SPI 的问题全部实例化。不管你用不用ServiceLoader 会把所有实现类都 new 一遍。无法排序。多个实现类的加载顺序取决于 classpath不可控。无法按条件过滤。不能根据运行时参数只加载某一个实现。无生命周期管理。加载后没有统一的销毁机制。Nacos SPI 的工作方式// NacosServiceLoader 的加载NacosServiceLoaderIdentityContextBuilderloaderNacosServiceLoader.newServiceLoader(IdentityContextBuilder.class);// 获取所有实现按 order 排序CollectionIdentityContextBuilderbuildersloader.getSingletonServiceList();// 取第一个order 值最小的IdentityContextBuilderbuilderbuilders.iterator().next();特性Java SPINacos SPI加载方式ServiceLoader.load()NacosServiceLoader.newServiceLoader()实例化策略全量实例化按需实例化 单例缓存排序无classpath 顺序Order注解 或getOrder()方法过滤无按type属性过滤配置文件META-INF/services/META-INF/services/生命周期无initialize()shutdown()配置文件的路径是一样的都在META-INF/services/但 Nacos SPI 在加载时多了一层处理逻辑。扩展点加载流程源码走读NacosServiceLoader 的核心方法// com.alibaba.nacos.common.spi.NacosServiceLoaderpublicclassNacosServiceLoaderS{// 接口类型 → 实现类列表的缓存privatefinalMapClassS,CollectionSserviceMapnewConcurrentHashMap();// 创建新的 ServiceLoaderpublicstaticSNacosServiceLoaderSnewServiceLoader(ClassSservice){NacosServiceLoaderSloadernewNacosServiceLoader(service);loader.load();returnloader;}// 核心加载逻辑privatevoidload(){// 1. 通过 JDK ServiceLoader 找到所有实现类ServiceLoaderSjdkLoaderServiceLoader.load(service);// 2. 遍历并实例化for(Simpl:jdkLoader){// 3. 调用 initialize()如果有if(implinstanceofSpiExtension){((SpiExtension)impl).initialize();}// 4. 放入缓存serviceMap.computeIfAbsent(service,k-newArrayList()).add(impl);}// 5. 按 order 排序serviceMap.get(service).sort(Comparator.comparingInt(this::getOrder));}// 获取排序后的实现列表publicCollectionSgetSingletonServiceList(){returnserviceMap.getOrDefault(service,Collections.emptyList());}}加载时序你的插件实现类JDK ServiceLoaderNacosServiceLoaderNacos Server 启动你的插件实现类JDK ServiceLoaderNacosServiceLoaderNacos Server 启动newServiceLoader(IdentityContextBuilder.class)ServiceLoader.load(IdentityContextBuilder.class)扫描 META-INF/services/ 文件返回实现类迭代器new YourPluginImpl()initialize()如果实现了 SpiExtension按 getOrder() 排序返回排序后的实现列表排序机制order 值怎么确定Nacos SPI 的排序有两种方式按优先级从高到低方式一Order注解Order(1)// order 值越小优先级越高publicclassMyAuthPluginimplementsAuthPluginService{// ...}方式二getOrder()方法publicclassMyHealthCheckPluginimplementsHealthCheckProcessor{OverridepublicintgetOrder(){return100;// 值越小越靠前}}order 范围含义使用场景0 - 99最高优先级自定义插件覆盖默认行为100 - 999中等优先级常规扩展1000低优先级兜底/默认实现Nacos 内置的插件实现通常 order 值在 1000 以上。你写的自定义插件设成 1 就能覆盖默认行为。Nacos 的 12 个扩展点你只需要知道这 5 个Nacos 2.x 总共有 12 个 SPI 扩展点。大部分你不需要碰。实际生产中用到最多的是这 5 个扩展点接口用途鉴权插件AuthPluginService自定义登录认证方式身份上下文IdentityContextBuilder从请求中提取身份信息健康检查HealthCheckProcessor自定义健康检查协议数据源ExternalDataSourcePlugin替换 MySQL 为其他数据库配置变更通知ConfigChangeHook配置变更后触发自定义动作剩余 7 个扩展点DNS 服务、指标上报、日志扩展等属于高级定制场景日常开发很少用到。扩展点的插件目录nacos-server/ ├── plugins/ # 插件 jar 包放这里 │ ├── my-auth-plugin.jar │ ├── my-healthcheck-plugin.jar │ └── my-datasource-plugin.jar ├── conf/ │ └── application.properties └── target/ └── nacos-server.jar把插件的 jar 包放到plugins/目录下Nacos 启动时自动扫描加载。不需要改任何配置文件除了插件自身需要的配置参数。一张图带走Nacos SPI 加载全流程Nacos Server 启动扫描 plugins/ 目录加载所有 jar读取 META-INF/services/找到接口→实现类映射NacosServiceLoader实例化实现类调用 initialize()SpiExtension 接口按 Order / getOrder() 排序值越小优先级越高注册到扩展点 Map运行时按 order 调用优先使用 order 最小的实现Nacos Server 启动时扫描 plugins 目录 → 读 META-INF/services → 实例化 → 初始化 → 排序 → 注册。运行时按 order 取优先级最高的实现。不适用本文描述的情况Nacos 1.3.x 及以下。SPI 插件机制从 1.4.0 开始引入。1.3.x 没有 plugins 目录、没有 NacosServiceLoader。如果你需要自定义功能只能 fork 源码修改。Nacos 2.0.x 早期版本。2.0.0 引入了鉴权插件和数据源插件接口但接口在 2.0.x 的小版本迭代中有变更。如果你在 2.0.0 上开发的插件升级到 2.1.x 后可能需要适配接口变更。你们在 Nacos 上开发过自定义插件吗评论区留数字1开发过鉴权插件 2开发过健康检查插件 3开发过数据源插件 4还没开发过先收藏

相关新闻

ArcGIS 10.8 流域提取实战:基于30m DEM生成5级河网与子流域边界

ArcGIS 10.8 流域提取实战:基于30m DEM生成5级河网与子流域边界

2026/7/11 20:43:32

ArcGIS 10.8 流域提取实战:基于30m DEM生成5级河网与子流域边界水文分析是地理信息系统(GIS)在水资源管理、环境评估和灾害预防等领域的核心应用之一。通过数字高程模型(DEM),我们可以模拟地表水流的运动路…

锂离子电池组主动均衡方案与MP2672A应用实践

锂离子电池组主动均衡方案与MP2672A应用实践

2026/7/11 20:43:32

1. 项目背景与核心需求解析两节串联锂离子电池组在无人机、电动工具和便携式医疗设备中广泛应用,但电池单元间的电压不平衡问题长期困扰着工程师。这种不平衡轻则降低电池组容量利用率,重则引发过充过放的安全隐患。传统被动均衡方案通过电阻放电实现平衡…

MAX77654与PIC18F96J65的嵌入式电源管理方案

MAX77654与PIC18F96J65的嵌入式电源管理方案

2026/7/11 20:43:32

1. 项目背景与需求分析 在嵌入式系统设计中,电源管理一直是决定产品可靠性和续航能力的关键因素。MAX77654与PIC18F96J65的组合方案,正是针对需要高效能电源管理的智能设备而设计的经典搭配。我在多个工业物联网项目中验证过这套架构,其核心价…

数据库安全审计的AI增强:用NLP检测异常SQL访问模式

数据库安全审计的AI增强:用NLP检测异常SQL访问模式

2026/7/11 22:13:35

数据库安全审计的AI增强:用NLP检测异常SQL访问模式 一、"有人半夜两点用root账号select了用户表"——但可能只是一条漏网的正常SQL 传统数据库审计系统依赖规则匹配(Rule-Based):SELECT * FROM users 触发告警、DROP TA…

ADP5350 PMIC与STM32F412RE的嵌入式电源管理方案

ADP5350 PMIC与STM32F412RE的嵌入式电源管理方案

2026/7/11 22:13:35

1. 项目背景与核心需求在嵌入式系统开发中,电源管理一直是个既基础又关键的环节。我最近为一个工业级数据采集终端设计电源方案时,深刻体会到传统分立式电源设计的局限性——当系统需要同时处理锂电池充放电、多电压轨生成、动态功耗调节等功能时&#x…

openEuler/raspberrypi-build底层原理:自动扩展根分区实现机制详解

openEuler/raspberrypi-build底层原理:自动扩展根分区实现机制详解

2026/7/11 22:13:35

openEuler/raspberrypi-build底层原理:自动扩展根分区实现机制详解 【免费下载链接】raspberrypi-build Scripts of building images for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-build 前往项目官网免费下载:https:/…

面向泳池复杂动态场景的水面扰动抑制与时序行为校验工程方案研究

面向泳池复杂动态场景的水面扰动抑制与时序行为校验工程方案研究

2026/7/11 22:13:35

摘要可见光视觉溺水检测方案规模化落地过程中,水面波纹、阳光逆光、水体反光、人群重叠遮挡是造成误报、漏检最核心的环境干扰源。通用目标检测模型仅依靠单帧图像推理,缺少针对水体动态特征的前置过滤机制,在商用泳池、综合戏水场地极易产生…

基于L9958与STM32F7的高性能电机驱动方案

基于L9958与STM32F7的高性能电机驱动方案

2026/7/11 22:13:35

1. 项目背景与核心组件选型在工业自动化和机器人控制领域,电机驱动系统的性能往往决定了整个设备的响应速度、能效比和可靠性。这次我们要探讨的是基于L9958驱动芯片和STM32F746VG微控制器的电机控制方案,这套组合在高性能应用场景中展现了卓越的控制精度…

GB2312 编码转换实战:Python 脚本 10 行代码批量获取汉字机内码

GB2312 编码转换实战:Python 脚本 10 行代码批量获取汉字机内码

2026/7/11 22:03:35

GB2312编码转换实战:Python脚本10行代码实现汉字机内码批量获取在中文信息处理领域,GB2312编码标准扮演着至关重要的角色。作为最早的中文编码方案之一,它奠定了后续GBK、GB18030等编码体系的基础。理解GB2312编码机制,特别是区位…

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南

2026/7/10 22:32:48

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gi…

6个月转型AI工程师:实战路径与核心技能

6个月转型AI工程师:实战路径与核心技能

2026/7/11 19:21:29

1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公…

YOLOv5模型剪枝与量化实战:边缘设备部署优化

YOLOv5模型剪枝与量化实战:边缘设备部署优化

2026/7/10 6:57:56

1. 项目背景与核心价值在计算机视觉领域,YOLOv5因其出色的实时检测性能成为工业界宠儿。但当我们尝试将其部署到边缘设备(如树莓派、Jetson Nano或手机终端)时,立刻会遇到两个致命问题:模型体积庞大(原始YO…

WechatDecrypt技术解析:深入理解微信数据库AES-256-CBC解密机制

WechatDecrypt技术解析:深入理解微信数据库AES-256-CBC解密机制

2026/7/11 0:02:03

WechatDecrypt技术解析:深入理解微信数据库AES-256-CBC解密机制 【免费下载链接】WechatDecrypt 微信消息解密工具 项目地址: https://gitcode.com/gh_mirrors/we/WechatDecrypt 在数字隐私日益重要的今天,微信聊天记录作为个人数字资产的重要组成…

5分钟搞定Kodi字幕难题:智能字幕插件让你追剧无忧 [特殊字符]

5分钟搞定Kodi字幕难题:智能字幕插件让你追剧无忧 [特殊字符]

2026/7/11 0:02:03

5分钟搞定Kodi字幕难题:智能字幕插件让你追剧无忧 🎬 【免费下载链接】zimuku_for_kodi Kodi 插件,用于从「字幕库」网站下载字幕 项目地址: https://gitcode.com/gh_mirrors/zi/zimuku_for_kodi 还记得那个深夜吗?你刚下载…

PostgreSQL 备份与恢复实战:从 pg_dump 到时间点恢复的生产级方案

PostgreSQL 备份与恢复实战:从 pg_dump 到时间点恢复的生产级方案

2026/7/11 0:02:03

PostgreSQL 备份与恢复实战:从 pg_dump 到时间点恢复的生产级方案 一、数据库备份最容易被忽略的问题,不是「有没有做备份」,而是「备份能不能恢复、恢复要多久、以及恢复后的数据对不对」 很多团队做数据库备份的方式是「写个 cron job&am…