Skip to main content
本文对常见的 HTTP 与 IoC 装饰器给出双视角说明:
  • 使用视角:如何在控制器/服务中使用
  • 内部视角:装饰器如何转化为元数据,如何影响容器解析与运行时行为

1. IoC 与对象作用域(核心)

这些装饰器定义了对象在容器中的“原型(Proto)”与生命周期,属于最基础的依赖注入体系。

1.1 @SingletonProto(params?)

  • 作用:声明“应用级单例”。应用启动创建(或首次使用后常驻),直到应用关闭才释放。
  • 适用场景:
    • 跨请求复用的昂贵资源:数据库连接池、Redis 客户端、第三方 SDK 客户端、HTTP 客户端等
    • 全局缓存、配置中心客户端、限流器、熔断器、监控/埋点上报器
    • 后台/定时任务执行器(长期存活、不会被释放)
  • 常用参数:accessLevel(默认 PRIVATE,如需被其他模块注入设为 PUBLIC)
  • 示例:
import { SingletonProto, AccessLevel } from '@eggjs/tegg';

@SingletonProto({ accessLevel: AccessLevel.PUBLIC })
export class RepoClient {}

1.2 @ContextProto(params?)

  • 作用:声明“请求级对象”。每次请求创建一个实例,请求结束后释放。
  • 适用场景:
    • 强依赖当前请求上下文(ctx)的业务服务:鉴权信息、traceId、租户、灰度/分流策略等
    • 请求内中间态缓存、一次性事务/会话编排
    • 需要读取 ctx 或与中间件链路协作的 AOP/策略对象
  • 常用参数:accessLevel(默认 PRIVATE)
  • 示例:
import { ContextProto } from '@eggjs/tegg';

@ContextProto()
export class OrderService {}

1.3 @Inject(token?) / @InjectOptional(token?)

  • 作用:声明依赖注入点,由容器在创建对象时自动解析并注入对应实例。
  • 区别:@InjectOptional 在依赖缺失时不会报错,注入为 undefined
  • 典型写法:构造器注入或属性注入。
import { Inject, InjectOptional } from '@eggjs/tegg';

export class BizService {
  constructor(@Inject() private repo: RepoClient,
              @InjectOptional() private cache?: CacheClient) {}
}
  • 关键规则(非常重要):
    • ContextProto 可以注入 SingletonProto(和同为 ContextProto 的对象)
    • SingletonProto 不能注入 ContextProto(单例跨请求常驻,禁止持有短生命周期对象)

1.4(进阶)@MultiInstanceProto(params?)

  • 作用:声明“多实例作用域”,可用于按租户/地域等维度隔离实例。
  • 说明:高级场景使用,需结合自定义实例查找与生命周期管理,日常开发可不使用。

2. 控制器与路由(HTTP)

由 controller 插件提供,用于声明控制器、路由与参数绑定。

2.1 @HTTPController(options)

  • 作用:声明控制器类,指定基路径、Host 约束、控制器级中间件等。
  • 常用字段:pathhostmiddleware
import { HTTPController, Middleware } from '@eggjs/tegg';

@HTTPController({ path: '/api/v1' })
@Middleware(authMiddleware)
export class UserController {}

2.2 @HTTPMethod 及快捷装饰器

  • 作用:声明方法级路由(HTTP 动作 + 路径)。
  • 使用方式:可统一用 @HTTPMethod({ method: 'GET', path: '/users/:id' }),也可使用快捷装饰器(若已启用):@GET('/users/:id')@POST('/users') 等。
import { HTTPMethod } from '@eggjs/tegg';

@HTTPMethod({ method: 'GET', path: '/users/:id' })
async getUser(@HTTPParam('id') id: string) { /* ... */ }

2.3 参数装饰器族(从请求中取值)

  • @HTTPBody():请求体
  • @HTTPParam(name):路径参数
  • @HTTPQuery(name) / @HTTPQueries():查询参数(单个/全部)
  • @HTTPHeaders(name):请求头
  • @Cookies(name):cookie
  • @Request() / @Context():注入原始 Request / 框架上下文对象
@HTTPMethod({ method: 'POST', path: '/users' })
async create(
  @HTTPBody() body: any,
  @HTTPHeaders('x-request-id') rid: string,
  @Context() ctx: any,
) { /* ... */ }

2.4 @Middleware(mw)(控制器级/方法级)

  • 作用:为控制器或方法声明中间件链;支持数组、按声明顺序执行。
  • 场景:认证、鉴权、灰度、审计、参数校验、读写分离、埋点等。
  • 示例:
@HTTPController({ path: '/api/v1' })
@Middleware([authMiddleware, logMiddleware])
export class UserController {}

2.5 @Host(pattern)

Host 注解,用于指定 HTTP 方法仅在 host 匹配时执行。 可以添加在类/方法上。添加在类上时,对类上所有方法生效,添加在方法上时,只对当前方法生效。方法上的注解可以覆盖类上的注解
import { Host } from '@eggjs/tegg';
@Host('foo.eggjs.com')
export class FooController {
  // 仅能通过 foo.eggjs.com 访问
  async hello() {
  }

  // 仅能通过 bar.eggjs.com 访问
  @Host('bar.eggjs.com')
  async bar() {
  }
}

3. 生命周期(核心/扩展)

3.1 @LifecycleInit

  • 作用:对象完成依赖注入后、对外提供服务前执行初始化逻辑(如预热连接、加载索引/字典)。
  • 场景:单例对象在应用启动阶段的预热;或上下文对象在首次使用前的准备工作。
import { SingletonProto, LifecycleInit } from '@eggjs/tegg';

@SingletonProto()
export class DictService {
  @LifecycleInit()
  async init() { /* 预热字典/连接等 */ }
}

4. 任务与模型(官方插件,按需使用)

4.1 @Schedule(…)(schedule 插件)

  • 作用:声明定时任务类,框架会按配置周期触发其实例的 subscribe 方法。
  • 适用场景:数据同步、清理、归档、重试补偿等后台任务。
  • 导入路径:从聚合包引入 @eggjs/tegg/schedule
参数说明(与实现保持一致):
  • param: ScheduleParams<T>
    • type: 'worker' | 'all'(或 ScheduleType.WORKER | ScheduleType.ALL)——在单个 worker 进程执行,或所有 worker 均执行。
    • scheduleData
      • Interval 定时:{ interval: string | number }(如 '10s'60000)。
      • Cron 定时:{ cron: string, cronOptions?: any }(标准 cron 表达式)。
  • options?: ScheduleOptions
    • immediate?: boolean 启动后立即执行一次(默认 false)。
    • disable?: boolean 关闭此任务(默认 false)。
    • env?: string[] 指定仅在这些环境运行。
使用示例:
import { Schedule, ScheduleType, type ScheduleSubscriber } from '@eggjs/tegg/schedule';

// 每 10 秒运行一次,只在本地和测试环境运行,启动时立即跑一轮
@Schedule({
  type: ScheduleType.WORKER,
  scheduleData: { interval: '10s' },
}, {
  immediate: true,
  env: [ 'local', 'test' ],
})
export class CleanTmpJob implements ScheduleSubscriber {
  async subscribe() {
    // 执行清理逻辑
  }
}
import { Schedule, ScheduleType, type ScheduleSubscriber } from '@eggjs/tegg/schedule';

// 每小时第 0 分钟运行一次,所有 worker 执行
@Schedule({
  type: ScheduleType.ALL,
  scheduleData: { cron: '0 0 * * * *' },
})
export class HourlyReportJob implements ScheduleSubscriber {
  async subscribe() {
    // 执行汇总/上报逻辑
  }
}
实现要点:装饰器内部会将类标记为单例并提升访问级别为 PUBLIC,框架根据 type/scheduleData/options 注册与调度该任务。

4.2 @Model(…)(orm 插件)

  • 作用:声明 ORM 模型(基于 leoric),并绑定到指定数据源/表名。
  • 适用场景:表模型定义、DAO 封装、领域仓储实现等。
  • 导入路径:从聚合包引入 @eggjs/tegg/orm
模型定义:
import { Model, Attribute } from '@eggjs/tegg/orm';
import { Bone, DataTypes } from 'leoric';

@Model({
  dataSource: 'test', // 可选:不配置则使用默认数据源
  // tableName: 'pkgs', // 可选:缺省按类名推导
})
export class Pkg extends Bone {
  @Attribute(DataTypes.STRING)
  name: string;

  @Attribute(DataTypes.STRING)
  desc: string;

  // 可选:模型生命周期钩子
  static beforeCreate(instance: Pkg) {
    instance.name += '_before_create_hook';
  }
}
在 Service 中注入并使用模型:
import { Inject, SingletonProto } from '@eggjs/tegg';
import { Pkg } from './model/Pkg';

@SingletonProto()
export class PkgService {
  @Inject()
  Pkg: typeof Pkg;

  async createPkg(data: { name: string; desc: string }) {
    return await this.Pkg.create(data as any);
  }

  async findPkg(name: string) {
    return await this.Pkg.findOne({ name });
  }
}
使用提示:需启用 ORM 插件并配置数据源(datasource),随后即可通过模型静态方法 create/findOne/update 等进行读写。
说明:上述为代表性装饰器,更多装饰器与高级特性(如 AOP 切面相关装饰器)请查阅对应插件的 README。

5. 选型与最佳实践

  • 是否依赖 ctx(请求信息)
    • 需要 → 使用 @ContextProto
    • 不需要/需跨请求复用 → 使用 @SingletonProto
  • 依赖方向
    • ContextProto 可注入 SingletonProto(以及同为 ContextProto 的对象)
    • SingletonProto 不可注入 ContextProto(避免生命周期倒挂)
  • 性能与资源
    • 重/长连接资源放单例集中管理;请求内临时状态放上下文对象
  • 访问级别(accessLevel)
    • 默认 PRIVATE 仅模块内可见;跨模块注入时设为 PUBLIC

6. 快速参考

  • IoC:@SingletonProto@ContextProto@Inject@InjectOptional
  • 控制器:@HTTPController@HTTPMethod(或 @GET/@POST 等)、参数装饰器族、@Middleware@Host
  • 生命周期:@LifecycleInit
  • 任务与模型(插件):@Schedule@Model