news 2026/9/10 13:48:59

Backstage 后端插件(Backend Plugin)架构全解:从 `createBackendPlugin` 到插件隔离规则

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Backstage 后端插件(Backend Plugin)架构全解:从 `createBackendPlugin` 到插件隔离规则

Backstage 后端插件(Backend Plugin)架构全解:从createBackendPlugin到插件隔离规则

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

Backstage 的插件(Plugin)是后端系统的核心功能单元:Catalog、Scaffolder、Notifications 等所有业务能力都由插件提供。本文以 docs/backend-system/architecture/04-plugins.md 为主干,结合仓库内@backstage/backend-plugin-api的源码实现与真实插件(如 notifications-backend)的代码,系统讲解插件的定义方式、注册机制、安装流程、配置约定与生产级插件必须遵循的可扩展性与隔离性规则。读完本文,你将能够独立编写、安装、配置并正确架构一个 Backstage 后端插件。

上图展示了 Backstage 后端系统的几大构建模块:Backend(后端实例)、Plugins(插件)、Services(服务)、Extension Points(扩展点)与 Modules(模块),插件与插件之间只能通过网络通信。

插件在后端系统中的定位

在后端系统架构(01-index.md)中,插件是提供实际业务功能的模块。理解插件,需要先把握以下几点定位:

  • 插件是功能的载体:默认的 Backstage 工程会把所有插件安装在同一个后端(backend)实例中,但也可以拆分为多个后端,每个后端承载一个或多个插件(02-backends.md)。
  • 插件彼此完全独立:每个插件与其他插件不存在任何代码层面的直接通信,只能通过网络调用交互。因此每个插件都可以被看作一个独立的微服务(microservice)。
  • 服务(Service)为插件提供公共能力:插件不需要从零实现日志、数据库、配置读取等基础设施,而是通过服务引用来获取实现。内置服务统一通过coreServices暴露(详见 core services 总览)。

定义插件:createBackendPlugin

插件使用createBackendPlugin函数创建,通常从一个插件包(plugin package)中导出。createBackendPlugin位于@backstage/backend-plugin-api包,其类型定义与实现位于 packages/backend-plugin-api/src/wiring/createBackendPlugin.ts 与 packages/backend-plugin-api/src/wiring/types.ts。

一个最简插件的定义如下(取自原文档示例):

// plugins/example-backend/src/plugin.ts import { coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; export const examplePlugin = createBackendPlugin({ pluginId: 'example', register(env) { env.registerInit({ deps: { logger: coreServices.logger, }, async init({ logger }) { logger.info('Hello from example plugin'); }, }); }, });

每个插件都必须具备:

  1. pluginId:插件的 ID,必须与包名中的插件 ID 一致(去掉-backend后缀)。ID 需符合 kebab-case 命名,仅允许字母、数字和短横线,且以字母开头(详见 08-naming-patterns.md)。
  2. register方法:接收一个env对象,用于声明插件的对外表面。

register回调中的三个关键注册点

从 types.ts 中的BackendPluginRegistrationPoints接口可以看到,envreg)提供以下能力:

方法用途
registerInit({ deps, init })注册初始化函数,在后端启动时运行;deps声明服务依赖,init回调接收解析后的依赖实例
registerExtensionPoint(ref, impl)注册扩展点实现,供模块(Module)扩展插件能力(见 05-extension-points.md)
registerConnection(registration)(内部)声明插件需要消费的连接类型

源码层面的校验逻辑

createBackendPlugin的实现中(createBackendPlugin.ts),有几点值得注意:

  • ID 校验:若pluginId不匹配ID_PATTERN,会打印警告提示尽快修改;若连宽松的旧模式ID_PATTERN_OLD都不匹配,则直接抛出Invalid pluginId错误。
  • registerInit只能调用一次:重复调用会抛出registerInit must only be called once
  • 必须在register中调用registerInit:如果注册结束时没有初始化函数,会抛出registerInit was not called by register in <pluginId>
  • registerExtensionPointregisterInit的顺序约束registerExtensionPoint必须在registerInit之前调用,否则报错。
  • 返回结构createBackendPlugin返回一个InternalBackendRegistrations类型的BackendFeature对象,其内部通过getRegistrations()惰性生成type: 'plugin-v1.1'的注册描述(包含pluginIdextensionPointsconnectionsinit),这使插件直到被真正加入后端时才完成注册描述的计算。

init中的依赖注入

registerInitdeps参数用于声明服务依赖,init回调则接收解析好的依赖对象。在上面的示例中,插件声明了对 logger 服务的依赖——这是所有 Backstage 后端插件可用的核心服务之一。完整的内置服务清单参见 core services 总览,包括 Auth、Cache、Database、Discovery、Http Router、Scheduler、Url Reader 等。插件自然也可以依赖其他库导出的服务(例如 notifications 插件依赖@backstage/plugin-signals-nodesignalsServiceRef@backstage/plugin-catalog-nodecatalogServiceRef)。

将插件安装进后端实例

createBackendPlugin的返回值(如上例中的examplePlugin)是一个工厂函数,用于创建实际的插件实例。在后端实例中安装插件:

import { examplePlugin } from 'backstage-plugin-example-backend'; backend.add(examplePlugin);

后端的创建与启动流程(02-backends.md)大致如下:

import { createBackend } from '@backstage/backend-defaults'; import scaffolderPlugin from '@backstage/plugin-scaffolder-backend'; // 创建后端实例 const backend = createBackend(); // 安装所需功能(插件、模块或服务工厂) backend.add(import('@backstage/plugin-catalog-backend')); // 也可以使用显式引用安装 backend.add(scaffolderPlugin); // 启动后端:初始化所有功能,并校验是否存在循环依赖等冲突 backend.start();

注意backend.add()既可以接收同步的插件实例,也可以接收import('...')动态导入(返回 Promise)。后端在启动时会对所有功能做冲突校验(例如确保不存在循环依赖)。

默认导出约定:按包名引用插件

按约定,每个插件包都应把插件实例作为包的默认导出:

// plugins/example-backend/src/index.ts export { examplePlugin as default } from './plugin.ts';

这样便可以直接通过包名引用安装插件,无需关心具名导出的名字:

backend.add(import('backstage-plugin-example-backend'));

这一约定与包结构相互配合:plugin-<pluginId>-backend包承载后端插件实现,plugin-<pluginId>-node包承载扩展点与其他工具(详见 architecture-overview.md 的包架构说明)。

使用静态配置定制插件

为了让插件可定制,应优先使用静态配置(docs/conf/defining.md)。按约定,插件应把配置放在与插件 ID 一致的一级配置键下。例如,上面的示例插件可以这样配置:

example: message: Welcome to the example plugin

在插件代码中,通过coreServices.rootConfig读取该配置(对应RootConfigService,详见 root-config 文档)。当静态配置不足以表达复杂的定制需求时,可以转而注册扩展点(Extension Point)来暴露更深层的定制能力,扩展点机制在 05-extension-points.md 中详细讲解。

插件规则(Rules of Plugins)

以下规则适用于 Backstage 插件生态中生产环境部署的插件。凡是维护在@backstage命名空间下的插件都应遵守,也推荐所有广泛分发的插件遵循。开发或测试环境是例外,可以为了简化开发流程而走捷径。

可扩展(Scalable)

插件必须始终面向水平扩展设计。这意味着:

  • 不要在内存中保存任何状态;
  • 如果必须保存状态,要确保状态在多个实例间的复制不会成为问题;
  • 插件要么无状态(stateless),要么把状态存放在外部服务(如数据库)中。

这样当某个插件的负载增长时,可以横向增加该插件的实例数,而不必担心实例间状态不一致。

隔离(Isolated)

插件绝不能通过代码与其他插件直接通信,只能通过网络通信。若插件希望为其他插件或模块暴露外部接口,推荐通过 node-library 包(包角色说明见 docs/tooling/cli/02-build-system.md#package-roles)实现:

  • 该库应导出 API 客户端服务(API client service)来调用你的插件,或导出类似结构;
  • 这样,其他插件通过服务依赖(Service Ref)获得 API 客户端,而通信仍走网络层,保持插件之间的隔离边界。

这一规则正是“每个插件可视为独立微服务”架构原则的落地:可独立部署、独立扩展、独立演进。

真实案例:notifications 后端插件

仓库中的 notifications 插件(plugins/notifications-backend/src/plugin.ts)是一个很好的综合范例,它同时运用了插件、服务依赖、扩展点与配置读取:

  • 插件定义createBackendPlugin({ pluginId: 'notifications', register(env) { ... } })
  • 注册扩展点env.registerExtensionPoint(notificationsProcessingExtensionPoint, processingExtensions),向模块暴露addProcessorsetNotificationRecipientResolver能力;
  • 依赖多个服务initdeps同时声明了核心服务(coreServices.authcoreServices.httpAuthcoreServices.loggercoreServices.databasecoreServices.rootConfigcoreServices.scheduler)与跨插件服务(signalsServiceRefcatalogServiceRefactionsRegistryServiceRef);
  • 在 init 中完成装配:创建数据库存储、挂载 HTTP 路由(httpRouter.use(...))、配置健康检查策略、启动定时清理任务(NotificationCleaner)并注册通知相关 Actions。

从中可以清晰看到插件register阶段只做“声明”(注册扩展点、声明 init),真正的资源创建与业务装配全部推迟到init阶段,这正是新后端系统把“注册”与“初始化”分离的设计意图。

命名模式速查

插件相关的命名需要遵循统一模式(完整表格见 08-naming-patterns.md):

描述模式示例
插件导出名<camelId>PlugincatalogPluginuserSettingsPlugin
插件 ID'<kebab-id>''catalog''user-settings'
扩展点接口<PluginId><Name>ExtensionPointCatalogProcessingExtensionPoint
扩展点引用<pluginId><Name>ExtensionPointcatalogProcessingExtensionPoint
服务接口<Name>ServiceLoggerServiceDatabaseService
服务引用<name>ServiceRefloggerServiceRef
服务工厂<name>ServiceFactoryloggerServiceFactory

核心服务的引用并不直接命名为loggerServiceRef,而是统一通过coreServices.logger形式从@backstage/backend-plugin-api导出,这也是插件中声明依赖的标准写法。

小结

Backstage 后端插件以createBackendPlugin为入口,以register阶段声明扩展点与初始化依赖、init阶段装配业务能力为基本流程,并通过默认导出约定简化安装。生产级插件必须坚持无状态/外部化存储以实现水平扩展,坚持网络通信以实现插件间隔离。理解这些机制,是编写高质量 Backstage 插件、合理拆分多后端部署的起点;关于如何通过扩展点与模块进一步丰富插件能力,请继续阅读 05-extension-points.md 与 06-modules.md。

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 13:47:33

mise bootstrap repos:在 mise.toml 中声明式管理 Git 仓库克隆与更新

mise bootstrap repos&#xff1a;在 mise.toml 中声明式管理 Git 仓库克隆与更新 【免费下载链接】mise dev tools, env vars, task runner 项目地址: https://gitcode.com/GitHub_Trending/mi/mise mise 的 bootstrap 系统可以在 [bootstrap.repos] 配置块中声明 Git …

作者头像 李华
网站建设 2026/9/10 13:45:05

Android ResolverActivity机制与默认应用自动设置详解

1. 项目概述ResolverActivity是Android系统中一个关键的系统组件&#xff0c;它负责处理当多个应用都能响应同一操作时的选择逻辑。作为系统默认启动流程的重要组成部分&#xff0c;ResolverActivity的自动设置机制直接影响着Android设备的用户体验和应用交互的流畅性。在实际开…

作者头像 李华
网站建设 2026/9/10 13:44:50

PoH协议:Web3去中心化身份验证技术解析

1. PoH&#xff08;Proof of Humanity&#xff09;的本质与价值PoH&#xff08;人性证明&#xff09;是Web3领域最具革命性的身份验证协议之一。这个由区块链开发者社区提出的创新方案&#xff0c;试图解决数字世界最根本的问题&#xff1a;如何在不依赖中心化机构的前提下&…

作者头像 李华