服务端 API:生命周期(Lifecycle)

页面摘要: 服务端 API 包含 3 个生命周期函数。使用 register() 在应用完全初始化之前声明能力,使用 bootstrap() 在 Strapi 初始化后运行逻辑,使用 destroy() 在关闭时清理资源。每个函数都接收 { strapi } 作为参数。

生命周期函数控制插件服务端逻辑在 Strapi 应用启动和关闭序列中的运行时机。它们与路由、控制器、服务和其他服务端块一起从 服务端入口文件 导出。

WARNING

在深入阅读本页概念之前,请确保你已经:

启动序列

了解每个生命周期的运行时机,有助于你将正确的代码放在正确的位置:

Server API lifecycle diagram

PhaseWhat is available in your plugin
2. Registerstrapi 对象可用,但数据库尚未初始化,路由也尚未初始化
4. Bootstrap完整运行时:数据库已初始化、路由已初始化、服务与内容类型已加载、其他插件可用
5. Shutdown关闭正在进行中;在此 hook 中,在 Strapi 完成停止之前释放资源
NOTE

每个生命周期函数对每个插件实例调用一次。如果同一插件实例的生命周期被第二次调用(例如在自定义测试中),Strapi 会抛出错误。这不会在正常操作中发生。

register() {#register}

类型: Function

register() 在启动早期运行,在数据库初始化之前,也在路由初始化之前。

使用 register() 来:

  • 注册 自定义字段 的服务端部分
  • 注册数据库迁移
  • 在 Strapi HTTP 服务端上注册服务端中间件(例如 strapi.server.use(...))
  • 在 bootstrap 之前扩展另一个插件的内容类型或接口

JavaScript

'use strict';

module.exports = ({ strapi }) => {
  // Register a server-level middleware early in startup
  strapi.server.use(async (ctx, next) => {
    ctx.set('X-Plugin-Version', '1.0.0');
    await next();
  });
};

TypeScript

import type { Core } from '@strapi/strapi';

export default ({ strapi }: { strapi: Core.Strapi }) => {
  // Register a server-level middleware early in startup
  strapi.server.use(async (ctx: any, next: () => Promise<void>) => {
    ctx.set('X-Plugin-Version', '1.0.0');
    await next();
  });
};

bootstrap()

类型: Function

bootstrap() 在模块生命周期注册(插件/API)、数据库初始化、路由初始化以及 Content API 操作注册之后运行。

使用 bootstrap() 来:

  • 用初始数据填充数据库
  • 使用 strapi.service('admin::permission').actionProvider.registerMany(...) 注册管理面板 RBAC 操作
  • 注册定时任务(cron jobs)
  • 订阅数据库生命周期事件
  • 调用你的插件或其他插件的服务
  • 设置需要先注册其他插件的跨插件集成

JavaScript

'use strict';

module.exports = async ({ strapi }) => {
  // Register admin RBAC actions for this plugin
  await strapi.service('admin::permission').actionProvider.registerMany([
    {
      section: 'plugins',
      displayName: 'Read',
      uid: 'read',
      pluginName: 'my-plugin',
    },
    {
      section: 'plugins',
      displayName: 'Settings',
      uid: 'settings',
      pluginName: 'my-plugin',
    },
  ]);
};

TypeScript

import type { Core } from '@strapi/strapi';

export default async ({ strapi }: { strapi: Core.Strapi }) => {
  // Register admin RBAC actions for this plugin
  await strapi.service('admin::permission').actionProvider.registerMany([
    {
      section: 'plugins',
      displayName: 'Read',
      uid: 'read',
      pluginName: 'my-plugin',
    },
    {
      section: 'plugins',
      displayName: 'Settings',
      uid: 'settings',
      pluginName: 'my-plugin',
    },
  ]);
};

destroy()

类型: Function

destroy() 在 Strapi 实例关闭时调用。它是可选的。仅当你的插件持有需要显式清理的资源时才实现它。

使用 destroy() 来:

  • 关闭外部连接(数据库、消息队列、WebSocket 服务端)
  • 清除在 bootstrap() 中设置的 interval 或 timeout
  • 移除在插件生命周期内注册的事件监听器

JavaScript

'use strict';

module.exports = ({ strapi }) => {
  // Close an external connection opened in bootstrap()
  strapi.plugin('my-plugin').service('queue').disconnect();
};

TypeScript

import type { Core } from '@strapi/strapi';

export default ({ strapi }: { strapi: Core.Strapi }) => {
  // Close an external connection opened in bootstrap()
  strapi.plugin('my-plugin').service('queue').disconnect();
};

最佳实践

  • 保持 register() 轻量。 它在完整初始化之前运行。

  • 将数据库读/写放在 bootstrap() 中。 数据库在 bootstrap 阶段初始化,而不是在 register 期间。任何对 strapi.documents() 或查询数据库的服务的调用都应放在 bootstrap() 中。

  • 在 bootstrap() 中注册管理面板 RBAC 操作。 在该阶段使用 strapi.service('admin::permission').actionProvider.registerMany(...)。此时权限服务可用。Content API 操作由 Strapi 在同一阶段自动注册。

  • 始终将资源创建与 destroy() 配对。 如果你的插件在 bootstrap() 中打开了连接、注册了全局 interval 或附加了进程监听器,请实现 destroy() 来清理这些资源。这可以防止在测试和优雅重启期间发生资源泄漏。

  • 避免在 register() 中建立插件之间的硬依赖。 在注册时,其他插件的注册顺序无法保证。依赖于另一个插件已初始化的跨插件调用应放在 bootstrap() 中。

  • 优先使用服务而非内联逻辑。 将非平凡的 bootstrap 逻辑移入专用的服务方法中(例如 strapi.plugin('my-plugin').service('setup').initialize())。这使生命周期文件保持可读,且逻辑可测试。