
后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载在 Node.js 服务端应用中数据库连接、配置预生成、资源清理这类操作理应发生在应用启动与停止的特定阶段而不是在请求响应中重复处理。Midway 为此内置了一套完整的生命周期机制你只需在src/configuration.ts中实现ILifeCycle接口框架就会在启动、就绪、服务启动、关闭等关键节点自动调用对应方法。读完本文你将掌握 Midway 项目生命周期与对象生命周期的全部钩子函数、其底层执行顺序与超时机制并能在真实项目中完成连接建立、对象扩充、健康检查与优雅关闭的落地。项目生命周期概览Midway 为开发人员提供了四个项目级生命周期函数分别对应应用运行的不同阶段onConfigLoad配置文件加载阶段可以在这里修改、补充配置onReady依赖注入容器准备完毕可以在这个阶段做大部分初始化事情onServerReady服务启动完成此时可以拿到 server 与端口信息onStop应用即将关闭在这里清理资源onHealthCheck可选补充在健康检查被调用时执行用于上报组件/依赖的健康状态。这些钩子通过项目根目录下的src/configuration.ts文件实现ILifeCycle接口即可被框架在启动时自动加载。接口的完整定义如下与仓库源码 interface.ts 中ILifeCycle的定义保持一致interface ILifeCycle { /** * 在应用配置加载后执行 */ onConfigLoad?(container: IMidwayContainer, app: IMidwayApplication): Promisevoid; /** * 在依赖注入容器 ready 的时候执行 */ onReady(container: IMidwayContainer, app: IMidwayApplication): Promisevoid; /** * 在应用服务启动后执行 */ onServerReady?(container: IMidwayContainer, app: IMidwayApplication): Promisevoid; /** * 在应用停止的时候执行 */ onStop?(container: IMidwayContainer, app: IMidwayApplication): Promisevoid; /** * 在健康检查时执行 */ onHealthCheck?(container: IMidwayContainer): PromiseHealthResult; }从源码实现看每个钩子函数实际上还会接收到第三个参数options: LifeCycleInvokeOptions其中包含timeout当前生命周期超时配置与abortController中断信号这在后文超时机制一节会详细展开。底层执行顺序生命周期方法并非并行执行而是由框架的MidwayLifeCycleService按严格顺序调度。在 lifeCycleService.ts 中可以清晰看到完整执行链扫描所有Configuration()修饰的类创建实例并收集为生命周期实例列表并行绑定四类对象生命周期钩子onBeforeObjectCreated/onObjectCreated/onObjectInit/onBeforeObjectDestroy依次执行所有配置类的onConfigLoad()返回的数据通过configService.addObject()合并进配置依次执行onReady()调用frameworkService.runFramework()启动框架此时监听端口、启动 server依次执行onServerReady()。而在应用停止时stop 方法会先将生命周期实例列表倒序后依次执行onStop()再停止框架。也就是说onStop的执行顺序与启动阶段相反后初始化的组件会先被清理从而保证资源释放的对称性。onConfigLoad启动时修改配置onConfigLoad一般用于修改项目的配置文件比如根据运行时环境预生成部分配置、注入密钥等。它的返回值会被自动合并进全局配置// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { async onConfigLoad(): Promisevoid { // 直接返回数据会自动合并到配置中 return { test: 1 } } }此时在其他类中通过Config拿到的配置就包含了这段返回的数据例如Config(test)即可获取到1。这种异步初始化配置的更多玩法可参考 异步初始化配置 章节。从源码角度印证MidwayLifeCycleService在调用onConfigLoad时设置了resultHandler将每个配置类返回的非空数据通过configService.addObject(configData)合并到配置服务中见 lifeCycleService.ts。因此返回值的结构会作为配置对象的一部分直接暴露给Config注入。onReady容器就绪后的主要初始化入口onReady是大部分场景下都会使用到的生命周期。:::info 注意这里的 ready 指的是依赖注入容器 ready并不是应用 ready所以你可以对应用做任意扩展比如添加中间件、连接数据库等。 :::典型场景在初始化时提前连接数据库。由于配置类本身也是由容器管理的对象因此可以在其中通过Inject装饰器注入数据库连接工具类该实例包含connect和close两个函数// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { Inject() db: any; async onReady(container: IMidwayContainer): Promisevoid { // 建立数据库连接 await this.db.connect(); } async onStop(): Promisevoid { // 关闭数据库连接 await this.db.close(); } }这样我们就能在应用启动时建立数据库连接而不是在请求响应时再去创建同时在应用停止时也能优雅地关闭数据库连接避免连接泄漏。通过 registerObject 扩充注入对象除了消费容器中已有的对象onReady阶段还可以对默认注入的对象做扩充将三方包、外部实例注册进容器之后在任何类中都可以直接注入使用。// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from midwayjs/core; import * as sequelize from sequelize; Configuration() export class MainConfiguration implements ILifeCycle { async onReady(container: IMidwayContainer): Promisevoid { // 三方包对象 container.registerObject(sequelize, sequelize); } }在其他的类中可以直接注入使用export class IndexHandler { Inject() sequelize; async handler() { console.log(this.sequelize); } }这里container.registerObject注册的对象与Provide()创建的对象一样都遵循容器的依赖注入规则任何通过Inject声明同名标识符的类都能拿到该实例。onServerReady获取 server 与服务端口当需要获取框架的服务对象、端口等信息时就需要用到onServerReady。因为此时框架已完成启动frameworkService.runFramework()已执行完毕server 实例已经可用。以midwayjs/koa为例在启动时获取它的 Server// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from midwayjs/core; import * as koa from midwayjs/koa; Configuration({ imports: [koa] }) export class MainConfiguration implements ILifeCycle { async onServerReady(container: IMidwayContainer): Promisevoid { // 获取到 koa 中暴露的 Framework const framework await container.getAsync(koa.Framework); const server framework.getServer(); // ... } }这里的关键在于container.getAsync(koa.Framework)midwayjs/koa包导出的Framework类已被注册进依赖注入容器异步获取其单例后即可通过framework.getServer()拿到底层 HTTP Server进而读取监听端口、注册服务端事件或做端口相关操作。仓库测试夹具 base-app-object-lifecycle/src/configuration.ts 也演示了在onServerReady中通过App()拿到应用实例并设置属性的用法。onStop优雅清理资源应用即将关闭时onStop会被执行适合清理资源比如关闭数据库连接、断开消息队列、释放定时器等。// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer } from midwayjs/core; import * as koa from midwayjs/koa; Configuration({ imports: [koa] }) export class MainConfiguration implements ILifeCycle { Inject() db: any; async onReady(container: IMidwayContainer): Promisevoid { // 建立数据库连接 await this.db.connect(); } async onStop(): Promisevoid { // 关闭数据库连接 await this.db.close(); } }onHealthCheck健康检查上报当内置的健康检查服务调用状态获取 API 时所有组件的onHealthCheck方法都会被自动执行。每个组件可以在该方法中探测自己依赖的状态数据库、缓存、外部服务等并返回统一的HealthResult结构。下面模拟了一个 db 健康检查的方法// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, HealthResult } from midwayjs/core; Configuration({ namespace: db }) export class MainConfiguration implements ILifeCycle { Inject() db: any; async onReady(container: IMidwayContainer): Promisevoid { await this.db.connect(); } async onHealthCheck(): PromiseHealthResult { try { const result await this.db.isConnect(); if (result) { return { status: true, }; } else { return { status: false, reason: db is disconnect, }; } } catch (err) { return { status: false, reason: err.message, }; } } }上述onHealthCheck中调用了一个isConnect的状态检查根据结果返回了固定的HealthResult类型格式。HealthResult 与聚合结果HealthResult的定义位于 interface.ts必须包含status: boolean可选包含reason?: string失败原因。所有组件的检查结果会由MidwayHealthService.getStatus()聚合成HealthResultsstatus整体状态只要存在任一失败的组件即为falsenamespace第一个失败组件的命名空间reason第一个失败原因results每个组件的独立检查结果数组。从 healthService.ts 的实现可以看到两个强约束若某个onHealthCheck的返回值不是包含status字段的对象该组件会被记为status: false并提示configuration.onHealthCheck return value must be object and contain status field若方法抛错或超时则捕获异常并将reason记为错误信息。这些行为在仓库测试 feature.test.ts 中均有对应的断言验证。健康检查的注意事项注意外部调用onHealthCheck可能会非常频繁请尽可能保持检查逻辑的可靠性和效率确保不会对检查依赖有较大的压力。同时请自行处理检查超时后资源释放的逻辑避免资源频繁请求却未返回结果导致内存泄露的风险。例如在探测远端服务时应给探测请求自身设置合理的超时时间并在 catch 中兜底返回status: false。全局对象生命周期所谓对象生命周期指的是每个对象在依赖注入容器中创建、销毁的事件。通过这些生命周期我们可以在对象创建后、销毁时做一些统一操作例如给所有业务对象附加通用属性、统一替换对象、执行通用的初始化或清理逻辑。export interface IObjectLifeCycle { onBeforeObjectCreated(/**...**/); onObjectCreated(/**...**/); onObjectInit(/**...**/); onBeforeObjectDestroy(/**...**/); }ILifeCycle定义中已经包含了这些阶段ILifeCycle extends PartialIObjectLifeCycle所以直接在配置类中实现对应方法即可。:::caution 注意对象生命周期 API 会影响整个依赖注入容器以及业务的使用请谨慎操作。 :::完整接口见 interface.ts包含onBeforeBind、onBeforeObjectCreated、onObjectCreated、onObjectInit、onBeforeObjectDestroy五个阶段。需要强调的是这些钩子对容器中每一个对象生效属于全局拦截因此使用时要特别小心避免影响框架内部对象或产生意外的副作用。onBeforeObjectCreated实例创建前在业务对象实例创建前执行。注意框架内部的某些对象由于已经初始化无法被拦截。// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeCreatedOptions } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { async onBeforeObjectCreated(Clzz: new (...args), options: ObjectBeforeCreatedOptions): Promisevoid { // ... } }这里入参有两个参数Clzz当前待创建对象的原型类options一些参数参数如下:属性类型描述options.contextIMidwayContainer依赖注入容器本身options.definitionIObjectDefinition对象定义options.constructorArgsany[]构造器入参onObjectCreated实例创建后可替换对象在对象实例创建后执行这个阶段可以替换创建的对象也可以给对象附加属性。// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectCreatedOptions } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectCreatedOptions): Promisevoid { // ... } }这里入参有两个参数ins当前通过构建器创出来的对象options一些参数参数如下:属性类型描述options.contextIMidwayContainer依赖注入容器本身options.definitionIObjectDefinition对象定义options.replaceCallback(ins: any) void对象替换的回调方法示例动态添加属性// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectInitOptions): Promisevoid { // 每个创建的对象都会添加一个 _name 的属性 ins._name xxxx; // ... } }示例替换对象// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { async onObjectCreated(ins: any, options: ObjectInitOptions): Promisevoid { // 之后每个创建的对象都会被替换为 { bbb: aaa } options.replaceCallback({ bbb: aaa }); // ... } }第二个示例中replaceCallback是对象替换的关键一旦调用容器后续向消费者提供的将是替换后的新对象。这种机制常被用于 AOP、代理包装等场景但因为影响面是全局的务必确认替换逻辑对所有业务对象都安全。onObjectInit异步初始化完成后在对象实例创建后执行异步初始化方法后执行即在对象执行完Init()标记的初始化方法之后触发。// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { async onObjectInit(ins: any, options: ObjectInitOptions): Promisevoid { // ... } }这里入参有两个参数ins当前通过构建器创出来的对象options一些参数参数如下:属性类型描述options.contextIMidwayContainer依赖注入容器本身options.definitionIObjectDefinition对象定义:::info 在这个阶段也可以动态给对象附加属性、方法等和onObjectCreated的区别是这个阶段是在初始化方法执行之后。 :::onBeforeObjectDestroy对象销毁前在对象实例销毁前执行适合做对象级别的资源清理。// src/configuration.ts import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeDestroyOptions } from midwayjs/core; Configuration() export class MainConfiguration implements ILifeCycle { async onBeforeObjectDestroy(ins: any, options: ObjectBeforeDestroyOptions): Promisevoid { // ... } }这里入参有两个参数ins当前通过构建器创出来的对象options一些参数参数如下:属性类型描述options.contextIMidwayContainer依赖注入容器本身options.definitionIObjectDefinition对象定义超时机制从 v4 开始框架内置了超时机制防止某些生命周期函数阻塞应用启动。每个生命周期钩子都会在设定的时间内执行超时后由框架中断并记录避免单个卡死的初始化逻辑拖垮整个应用的启动/停止流程。默认超时时间不同生命周期方法有不同的默认超时时间生命周期方法默认超时时间配置项说明onConfigLoad10 秒core.configLoadTimeout配置加载阶段onReady30 秒core.readyTimeout容器准备阶段onServerReady30 秒core.serverReadyTimeout服务启动阶段onStop默认无限制core.stopTimeout应用停止阶段onHealthCheck1 秒core.healthCheckTimeout健康检查阶段这些默认值与仓库 config.default.ts 中的实际配置一一对应healthCheckTimeout: 1_000、configLoadTimeout: 10_000、readyTimeout: 30_000、serverReadyTimeout: 30_000。可以看到stopTimeout并未设置默认值因此在未配置时onStop不设超时上限如果希望停止阶段也有保护可以主动配置该项。自定义超时时间可以通过配置修改每个生命周期的超时时间:::tip 注意这个配置是全局的。 :::// src/config/config.default.ts export default { core: { // 配置加载超时毫秒 configLoadTimeout: 15_000, // 15秒 } } as MidwayConfig;单位是毫秒。同理可配置core.readyTimeout、core.serverReadyTimeout、core.healthCheckTimeout与core.stopTimeout。这些值在运行时由MidwayLifeCycleService通过configService.getConfiguration(core.xxxTimeout)读取见 lifeCycleService.ts并配合createPromiseTimeoutInvokeChain实现超时中断与错误记录。在生命周期中处理超时在生命周期方法中可以通过第三个入参获取到当前的超时配置以及中断信号从而在超时前主动感知并做兜底处理Configuration() export class MainConfiguration implements ILifeCycle { async onReady(container: IMidwayContainer, app: IMidwayApplication, options: { timeout?: number; abortController?: AbortController; }): Promisevoid { // 可以获取到超时配置 console.log(当前超时配置:, options.timeout); // 30000 // 可以监听中断信号 if (options.abortController) { options.abortController.signal.addEventListener(abort, () { console.log(生命周期被中断); }); } // 执行初始化逻辑 await this.initializeServices(); } }options.timeout即当前生命周期方法对应的超时毫秒数如onReady默认 30000options.abortController则携带中断信号。当执行超过时限时框架会触发abort你可以在监听回调中做日志记录、资源释放等收尾工作。这在初始化依赖外部服务、网络不确定的场景下尤为重要——即使初始化被中断也能保证已占用的资源不被泄漏。小结与推荐实践结合仓库源码与文档可以总结出几条实战建议初始化时机选择修改/补充配置用onConfigLoad依赖注入容器内的初始化连数据库、注册对象、加中间件用onReady需要拿 server、端口时用onServerReady关闭连接、释放资源用onStop。健康检查要轻量onHealthCheck会被健康检查 API 频繁调用且默认超时仅 1 秒务必保持探测逻辑高效并对超时与异常做好兜底返回合法的HealthResult必须含status字段。对象生命周期慎用onObjectCreated、onObjectInit等钩子作用于容器内所有对象适合做全局属性注入、代理替换但要评估对业务与框架内部对象的影响。善用超时保护为长耗时的初始化配置合理的core.*Timeout并在生命周期内监听abortController信号完成资源释放避免启动被阻塞或资源泄漏。如需继续深入可在仓库中查看生命周期服务的完整实现 lifeCycleService.ts、健康检查服务 healthService.ts、生命周期接口定义 interface.ts 以及对应的测试夹具 base-app-object-lifecycle/src/configuration.ts 与 app-with-health-check/src/configuration.ts。赞分享后端微服务云原生【免费下载链接】midway A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 项目地址https://gitcode.com/gh_mirrors/mi/midway点击查看免费下载相关推荐Chainlit 生命周期钩子应用启动与关闭事件处理Chainlit 生命周期钩子应用启动与关闭事件处理 你是否在开发 Python LLM 应用时遇到过资源管理难题启动时需要初始化模型关闭时必须释放连接人工智能大模型AI 应用后端前端python-diskcache核心API详解Cache、FanoutCache和DjangoCache的完整使用教程python diskcache核心API详解Cache、FanoutCache和DjangoCache的完整使用教程 python diskcache是一个后端ttf-parser实战构建自定义字体渲染引擎的10个步骤ttf parser实战构建自定义字体渲染引擎的10个步骤 ttf parser是一个高级、安全且零分配的TrueType字体解析器它为开发者提供了强大的字上一篇AutoTrain Advanced图像分割评估指标mIoU与Dice系数详解下一篇Markdown 新标签页插件使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考