当前位置: 首页 > news >正文

[Backstage] 后端服务 | 示例插件

第3章:后端服务

在上一章前端插件中,我们探讨了如何构建交互式用户界面,并向Backstage添加用户可见且可点击的新功能。

但当前端插件(或Backstage的任何部分)需要执行任务时,幕后会发生什么?例如,当软件目录需要获取实体数据时,或者当模板需要创建新仓库时?这些操作通常涉及与数据库通信、读取配置或在服务器上执行日志记录。

这就是后端服务的用武之地,它们是Backstage后端的支柱,提供了一套标准化的“工具包”,包含所有后端插件可以依赖的通用工具和功能

将Backstage后端想象成一个繁忙的工厂,有许多不同的部门(后端插件),每个部门生产特定的产品。每个部门都需要通用工具,例如叉车(用于数据库访问)、公告板(用于配置)或安全报告表(用于日志记录)。

与其让每个部门购买自己独特版本的这些工具,工厂的中央管理层(Backstage后端系统)提供了一套标准化、共享的高质量工具,所有部门都可以请求和使用。如果工厂决定升级叉车,它会集中进行,所有部门自动获得新的改进版本,而无需改变其操作方式。

后端服务解决了什么问题?

Backstage后端插件与任何服务器端应用一样,经常需要执行以下常见任务:

  • 日志记录:记录事件、错误或信息,用于调试和监控。
  • 配置:读取Backstage管理员定义的设置和参数。
  • 数据库访问:存储和检索数据。
  • 调度:在特定时间间隔运行后台任务。
  • 认证/授权:处理传入请求的安全问题。

如果没有标准化系统,每个后端插件将不得不:

  1. 重复造轮子:每个插件都会以自己的方式实现日志记录、连接数据库等功能,导致代码重复。
  2. 不一致:不同插件可能以不同格式记录日志,使用不同的数据库驱动,或以不同方式访问配置。
  3. 僵化:更改基础工具(例如从一种数据库切换到另一种)需要修改每个插件。

后端服务通过提供强大的依赖注入系统解决了这些问题。这意味着插件可以声明式需求(例如“我需要一个日志记录器”),而Backstage后端系统提供它插件无需关心具体实现

这使得插件更简洁、更一致,并且更容易在整体Backstage应用级别进行定制或扩展

让我们看一个实际用例:我们正在构建一个新的后端插件“我的示例插件”,并希望它:

  1. 在启动时记录一条消息。
  2. 从Backstage配置中读取自定义欢迎消息。
  3. (可选)将该消息保存到数据库。

后端服务如何帮助“我的示例插件”干净地实现这些功能?

后端服务的核心概念

后端服务是Backstage后端的基础。以下是其核心思想:

  • 共享、可复用的功能:它们是通用工具(例如日志记录、配置、数据库访问),任何后端插件或模块都可以请求和使用。
  • 服务接口与引用(ServiceRef:这是插件声明其需求的方式。ServiceRef就像合同或蓝图,定义了服务能做什么(其方法和类型),而不是如何做。这是插件请求“日志记录器”或“数据库客户端”的标准方式。
  • 服务工厂:这些是“车间”,负责创建服务的实际具体实现。当插件通过ServiceRef请求“日志记录器”时,ServiceFactory负责构建并提供实际的日志记录器实例。
  • 依赖注入(DI):这是核心机制。插件只需声明其依赖(所需的ServiceRef)。Backstage后端在插件启动时“注入”(提供)正确的服务实现。插件无需知道服务如何创建或配置,只需使用它。
  • 定制与覆盖:由于依赖注入,Backstage管理员可以轻松替换或定制服务实现,而无需修改插件代码。例如,可以通过为databaselogger服务提供不同的ServiceFactory,从内存数据库切换到PostgreSQL,或集成到企业日志系统。
  • 服务作用域:服务可以在不同的“作用域”中创建:
    • 插件作用域:为每个请求插件的服务创建新实例。这适用于需要为每个插件定制的服务(例如自动将插件ID添加到每条日志消息的日志记录器)。
    • 根作用域:创建单个服务实例,并在整个后端的所有插件和模块中共享。这适用于全局工具,如主配置读取器或主HTTP路由器。

解决用例:“我的示例插件”

让我们看看“我的示例插件”如何使用后端服务记录消息、读取配置并与数据库交互。

首先,我们需要创建一个简单的后端插件(例如在plugins/my-example-plugin/src/plugin.ts文件中):

// plugins/my-example-plugin/src/plugin.ts
import { createBackendPlugin, coreServices } from '@backstage/backend-plugin-api';export const myExamplePlugin = createBackendPlugin({pluginId: 'my-example', // 插件的唯一IDregister(env) {env.registerInit({// 这里声明插件所需的服务!// coreServices是Backstage提供的常见内置服务集合。deps: {logger: coreServices.logger,     // 用于记录消息config: coreServices.rootConfig, // 用于读取配置database: coreServices.database, // 用于数据库访问},// Backstage在插件初始化时自动提供这些服务async init({ logger, config, database }) {logger.info('我的示例插件正在启动!');// 1. 从Backstage配置中读取设置// 我们向'config'服务请求一个字符串值。const welcomeMessage = config.getOptionalString('myExamplePlugin.welcomeMessage') ?? '来自Backstage后端的问候!';logger.info(`配置的消息: "${welcomeMessage}"`);// 如果app-config.yaml中定义了'myExamplePlugin.welcomeMessage',则使用它。// 否则,默认为"来自Backstage后端的问候!"。// 2. 与数据库服务交互// 获取插件数据库的客户端(如连接)。const dbClient = await database.getClient();// 在实际场景中,这里会执行迁移和复杂查询。// 为简化,我们仅记录连接成功。logger.info('成功连接到我的示例插件的数据库。');// 3. 初始化完成时记录事件logger.info('我的示例插件完成初始化。');},});},
});

代码说明

  • createBackendPlugin({ pluginId: 'my-example', ... }):这是我们定义后端插件的方式。pluginId为其指定唯一名称。
  • env.registerInit({ deps: { ... }, async init({ ... }) { ... } }):这是插件启动逻辑的核心。
    • deps:这是我们声明“依赖”的地方。我们告诉Backstage:“我需要loggerconfig读取器和database客户端。”我们使用coreServices.loggercoreServices.rootConfigcoreServices.database,因为这些是Backstage提供的常见内置服务。
    • async init({ logger, config, database }):Backstage的依赖注入系统读取我们的deps列表。当启动插件时,它会自动创建(或查找现有)这些服务的实例,并将它们作为参数传递给init函数。然后我们可以在插件逻辑中直接使用loggerconfigdatabase

为了使插件运行,通常需要将其添加到主后端应用(例如在packages/backend/src/index.ts中):

// packages/backend/src/index.ts(简化)
import { createBackend } from '@backstage/backend-defaults';
import { myExamplePlugin } from './plugins/my-example-plugin'; // 我们的自定义插件const backend = createBackend();// 添加自定义插件
backend.add(myExamplePlugin());// ...(添加其他Backstage插件,例如catalog、scaffolder)...backend.start();

要为插件定义自定义消息,可以在app-config.yaml中添加以下内容:

# app-config.yaml
# ...其他配置...
myExamplePlugin:welcomeMessage: "欢迎使用我们的自定义Backstage设置!"

启动Backstage后端时,控制台会输出类似以下内容:

info: 我的示例插件正在启动! plugin=my-example
info: 配置的消息: "欢迎使用我们的自定义Backstage设置!" plugin=my-example
info: 成功连接到我的示例插件的数据库。 plugin=my-example
info: 我的示例插件完成初始化。 plugin=my-example

注意,每条日志消息都自动添加了plugin=my-example标签

这是默认logger服务的功能,它是插件作用域的,知道自己在为哪个插件服务。

底层原理:服务的生命周期

当我们将myExamplePlugin添加到Backstage后端时,一系列事件确保其所需的所有服务都正确设置和注入。

在这里插入图片描述

说明

  1. 后端注册插件Backstage后端启动并加载我的插件,因为通过backend.add(myExamplePlugin())添加了它。
  2. 插件声明依赖我的插件通过deps对象(loggerconfigdatabase)向Backstage后端声明所需服务。
  3. 后端解析服务Backstage后端查看每个声明的依赖及其ServiceRef(例如coreServices.logger)。确定服务是插件作用域(每个插件需要新实例)还是根作用域(所有插件共享一个实例)。
  4. 服务工厂行动
    • 对于插件作用域服务(如loggerdatabase),Backstage后端调用其服务工厂我的插件创建新实例。这些工厂可能配置服务(例如为日志记录器添加plugin=my-example,或连接到插件特定的数据库)。
    • 对于根作用域服务(如rootConfig),Backstage后端直接获取已存在的共享实例
  5. 注入:所有所需服务实例准备就绪后,Backstage后端通过将实例作为参数传递给我的插件init函数来“注入”它们。
  6. 插件执行我的插件使用完全配置且可直接使用的loggerconfigdatabase服务实例执行其init逻辑。

代码

后端服务的魔力来自几个核心构造:

  • createServiceRef:此函数用于定义ServiceRef——服务的蓝图或合同。

    • 文件位置packages/backend-plugin-api/src/services/definitions/coreServices.ts(核心服务)或插件的src/services/refs.ts

    • 示例(简化定义虚构的FooService

      // 定义FooService的功能
      export interface FooService {doSomething(input: string): Promise<string>;
      }// 创建FooService的引用(蓝图)
      export const fooServiceRef = createServiceRef<FooService>({id: 'example.foo', // 服务的全局唯一IDscope: 'plugin',   // 或'root'
      });
      
    • id:全局唯一标识符(通常为pluginId.serviceName)。

    • scope:定义服务是plugin作用域(每个插件新实例)还是root作用域(所有插件共享单个实例)。

  • createServiceFactory:此函数创建ServiceFactory——构建具体服务实现的“车间”。

    • 文件位置:通常在packages/backend-defaults/src/entrypoints/中用于默认实现,或在插件的后端包中。

    • 示例(简化FooService工厂)

      import { createServiceFactory } from '@backstage/backend-plugin-api';class DefaultFooService implements FooService {// ...实现...async doSomething(input: string): Promise<string> {return `处理: ${input}`;}
      }export const fooServiceFactory = createServiceFactory({service: fooServiceRef, // 链接到FooService蓝图deps: {}, // 此简单工厂无依赖factory() {// 此函数创建并返回实际服务实例return new DefaultFooService();},
      });
      
    • service:将工厂链接到特定ServiceRef

    • deps:列出此工厂自身构建服务所需的其他ServiceRef(例如数据库工厂可能依赖日志记录器)。

    • factory:实际创建并返回服务实例的函数。

  • coreServices:Backstage提供了一组始终可用的基本内置服务。“我的示例插件”中使用了这些服务。

    • 文档:完整列表及用法见核心后端服务API。
    • 示例包括:
      • coreServices.logger:记录信息。
      • coreServices.rootConfig:读取应用配置。
      • coreServices.database:与数据库交互。
      • coreServices.httpRouter:为插件注册HTTP端点。

通过替换这些默认的ServiceFactory实现,可以定制后端,如构建后端 - 自定义服务实现所述

例如,可以切换默认日志库或集成不同数据库系统,而无需修改插件代码。

结论

在本章中,我们揭秘了后端服务——支持Backstage服务器端功能的标准工具包。我们了解到这些服务通过强大的依赖注入系统,提供了日志记录、配置和数据库访问等基本工具

通过理解ServiceRefServiceFactory,我们现在掌握了后端插件如何声明需求,以及Backstage如何高效提供这些需求,使后端可扩展、一致且高度可定制。

接下来,我们将深入探讨现代应用的关键方面:Backstage如何处理**认证**,以确保用户和服务的安全访问。

http://www.dtcms.com/a/482849.html

相关文章:

  • 黑马商城day2-Docker
  • 赤水市住房和城乡建设局网站网站建设费专票会计分录
  • 前端页面权限管控-高阶组件
  • 什么是脚本语言?
  • AI智能体
  • 企业准备扩大规模时,如何选择第三方物流(3PL)合作伙伴
  • 阮一峰《TypeScript 教程》学习笔记——简介
  • Scope作用域
  • 网页设计网站名字上海企业电话查询
  • 论文阅读-IDFUZZ: Intelligent Directed Grey-box Fuzzing
  • [论文阅读]Progent: Programmable Privilege Control for LLM Agents
  • 内蒙古建设厅官网站自建本地网站服务器wordpress
  • 【愚公系列】《人工智能70年》078-AI塑造新人生(教育史上的“一场数字海啸“)
  • 数据分析-基础-二项分布
  • idea正则匹配搜索
  • Lombok @Data 注解在 Spring Boot 项目中的深度应用与实践指南
  • 电力电子技术 第一章——电力电子变换器
  • Spring Boot 项目启动报错:`Could not resolve type id ... no such class found` 终极解决方案!
  • 八方资源网做网站优化怎么样网络营销的主要传播渠道是
  • 基于python写的PDF表格提取到excel文档
  • 做贷款网站犯法吗wordpress 静态文件大
  • AWS CloudTrail:让每一次操作都“有迹可循”
  • 运动控制教学——5分钟了解雅可比矩阵!
  • BERT 中文外卖评价情感分析项目
  • [MySQL] 数据库的约束与设计
  • 用dw做的网页如何上传到网站wordpress安装后要删除哪些文件夹
  • dedecms 广告管理 js 网站变慢网站建设自查自评
  • 京东也要造车了
  • 株洲做网站三明注册公司
  • 网站开发 重庆南宁企业做网站