Skip to content

编写服务

0.2 起,服务即插件:服务以插件形态编写与装载,在插件主体内通过 context.share() 提升到根作用域,对全框架可见。服务插件享有完整的插件生命周期:启用、禁用、依赖等待与级联。

不稳定的 API

Saukko Core 的内置服务与服务插件 API 尚处于开发阶段,可能会发生重大变化。

编写一个服务插件

typescript
import type { Context } from '@saukkojs/core';

// 通过对 ServiceRegistry 进行扩展,让消费方获得正确的类型推导。
declare module '@saukkojs/core' {
    interface ServiceRegistry {
        myService: MyService;
    }
}

class MyService {
    method() {
        // ...
    }
}

export const name = 'my-service';
export default async function (context: Context) {
    await context.share('myService', new MyService());
}

要点:

  • share(name, service) 将服务登记进根作用域,所有权仍归插件的子作用域:随插件启用而启动、随禁用而摘除、随卸载而清理(详见 服务生命周期)。
  • 根作用域已有同名登记时 share 抛错(不静默遮蔽),安装随之失败,可修正后重新安装。
  • 缺省服务名为插件名context.share(new MyService())my-service 登记。显式不同名时(如上例),消费方需按服务名(myService)声明依赖,而非插件名。
  • 服务插件经 plugin.files / 插件依赖扫描装载;0.1 的 service.files / service.scopes 配置已废弃。

读取服务

消费方插件声明 inject 后经 context.get() 读取:

typescript
export const inject = ['myService'];
export const name = 'my-plugin';

export default function (context: Context) {
    context.get('myService')?.method();
}

未声明 inject 的服务也可沿作用域父链读取(全量可读);inject 的价值在于依赖编排:依赖未就绪时挂起等待、启动顺序保证、服务消失时的级联停止与恢复(见 依赖与诊断)。

内置服务

  • app: 应用服务,用于管理框架的生命周期。
  • logger: 日志服务,用于记录框架的日志。
  • config: 配置服务,用于管理框架的配置。
  • storage: 存储服务,用于管理框架的持久化数据。
  • database(WIP): 数据库服务,用于管理框架的数据库连接。
  • plugin: 插件服务,用于管理框架的插件。

关于 app 服务

为了让框架更加灵活,我们将 app 也设计为一个服务。这使得用户可以更加方便地管理框架的生命周期。

底层装配:register 与 provide

内置服务的装配(injectionProvider)仍使用作用域底层 API:

  • scope.register(name, target):惰性注册,首次 get 时实例化,构造依赖按静态 inject 沿父链解析;
  • scope.provide(name, service):立即登记并纳入作用域生命周期管理,覆盖同名服务时触发联动重启。

这两个 API 面向框架装配与测试场景。用户服务请优先使用服务插件 + share,以获得启用/禁用开关、依赖等待与级联恢复语义。

同时,我们会在下个版本中对内置服务与装配方法做出调整。

Saukko.js 系列项目均使用 Apache 2.0 协议开源。