Skip to content

插件系统

插件系统是 SharwAPI 的核心。本文将解析插件是如何被主程序发现、加载以及管理其生命周期的。

加载机制

主程序通过 AssemblyLoadContext (ALC) 技术来实现插件的隔离加载。该过程完全自动化,包含以下四个步骤:

  1. 目录扫描: 主程序启动时,自动检查根目录下的 plugins 文件夹。
  2. 上下文创建: 为扫描到的每一个插件 .dll 文件,创建一个独立的 PluginLoadContext(隔离环境)。
  3. 隔离加载:
    • 将插件程序集及其依赖加载到各自的上下文中。
    • 智能解析: 插件自身的依赖(如 Newtonsoft.Json v13.0)仅在当前上下文中可见;而共享库(如 Sharw.Contracts)会自动回退到主程序上下文,确保类型兼容。
  4. 实例创建: 在隔离环境中查找实现了 IApiPlugin 接口的类,并创建其实例。
    • 当前限制:每个插件 DLL 仅会加载第一个被发现的 IApiPlugin 实现类。
    • 建议:一个 DLL 只放一个插件主类,避免多个实现导致只有首个实现被加载。
  5. 依赖检查:
    • 遍历所有已加载的插件,检查其 Dependencies 属性声明的依赖项。
    • 存在性检查: 确保依赖的插件已加载。
    • 版本兼容性: 验证依赖插件的 Version 是否满足声明的版本范围 (支持 [1.0, 2.0)1.* 等格式)。
    • 自动卸载: 若依赖未满足,主程序会记录错误日志并将该插件从活动列表中移除,防止运行时错误。
  6. 插件运行: 通过依赖检查的插件正式进入运行状态。

关于依赖问题

从 v0.2.0 版本开始的 SharwAPI 采用 独立上下文 (AssemblyLoadContext) 技术来实现插件的隔离加载。 这彻底解决了不同插件使用同一个第三方库的不同版本等依赖问题,因为它们各自的隔离环境里运行,互不干扰。

但 v0.2.0 以前版本的 SharwAPI 采用 共享加载上下文 (Shared Context) 策略。 这意味着所有插件和主程序运行在同一个“环境”中。如果插件 A 和插件 B 引用了同一个第三方库但版本不同,可能会导致版本冲突或运行时错误。

隔离规范

为了防止插件之间互相干扰,SharwAPI 采用以下隔离策略:

配置隔离 (物理隔离)

SharwAPI 摒弃了传统的全局 appsettings.json 混合配置模式,转而采用 独立文件配置

  • 机制:主程序启动时,会自动读取 config/ 目录下与插件同名的 JSON 文件(例如 config/sharw.demo.json)。
  • 注入:在调用 RegisterServices 时,传递给插件的 configuration 参数将 仅包含 该文件的内容。
  • 优势:插件无需担心配置键名冲突(Key Collision),也无需使用 GetSection 进行多层嵌套,直接读取根节点即可。

路由的划分 (逻辑隔离)

RegisterRoutes 中定义接口时,强烈建议 开启自动前缀模式 (UseAutoRoutePrefix = true)。 这能确保你的所有 API 都被安全地限制在 /api/{插件名}/ 之下,彻底杜绝路由冲突。

服务的命名 (逻辑隔离)

虽然代码逻辑已隔离,但 依赖注入 (DI) 容器 依然是全局共享的。在 RegisterServices 中注册服务时,仍建议使用 插件名 作为前缀。

  • 推荐: services.AddHttpClient("sharw.demo.client", ...)
  • 避免: services.AddHttpClient("client", ...) (容易被其他插件覆盖)

生命周期管理

插件的实例在整个应用运行期间是 全局唯一 (Singleton) 的。 这意味着 IApiPlugin 的实现类在内存中只有一个对象,主程序会一直持有它直到关闭。

关键生命周期钩子

插件通过实现以下四个方法,介入主程序的不同启动阶段:

  1. RegisterServices (注册服务)

    • 阶段: 应用构建前。
    • 作用: 向全局容器注册依赖服务(如数据库服务、后台任务)。
  2. Configure (配置管道)

    • 执行时机: 应用构建后,启动前。
    • 作用: 向 HTTP 请求处理管道中插入中间件(如日志记录、鉴权逻辑)。
  3. RegisterRoutes (映射路由)

    • 执行时机: 中间件配置后。
    • 作用: 定义面向用户的业务 API 接口(如 /api/demo/hello)。
    • 注意: 所有 HTTP 请求都会先经过 Configure 中定义的中间件,最后才会到达这里。详情请参考 请求处理流程
  4. RegisterManagementEndpoints (挂载后台)

    • 执行时机: 由调用方按需调用。
    • 作用: 定义仅供管理员使用的运维接口(如 /admin/plugin/demo/status)。这些接口通常用于检查插件是否存活、强制重载配置等运维操作,不面向普通用户开放。详情请参考 管理接口

开发工具说明

  • Swagger / OpenAPI UI 仅在开发环境启用:主程序仅在 IsDevelopment() 条件下挂载 Swagger 中间件与 UI。
  • 在生产环境中默认不会暴露 Swagger 页面,如需 API 文档能力应自行提供受控方案(例如受鉴权保护的文档网关)。