You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tsyringe中正确实现单例模式?解决@singleton()标记类重复实例化问题

解决Tsyringe中@singleton()装饰器失效的问题

我一眼就看出问题所在了——你手动调用的container.register直接覆盖了@singleton()装饰器的配置!

问题根源

当你给Foo类加上@singleton()装饰器时,Tsyringe已经自动帮你把这个类注册为单例生命周期的依赖了。但你后面又执行了:

container.register("Foo", { useClass: Foo });

这相当于重新注册了Foo这个依赖,而Tsyringe默认的注册生命周期是Transient(每次解析都创建新实例),这直接把之前@singleton()的配置给覆盖了,所以每次解析Bar的时候都会重新创建Foo的实例。

解决方案有两种,选一种适合你的就行:

方案1:移除手动注册Foo的代码

既然已经用@singleton()和@injectable()装饰了Foo,完全不需要再手动注册。同时,Bar里的注入可以直接用类本身,不用字符串令牌:

修正后的代码:

  • Foo.ts(保持不变)
import { injectable, singleton } from "tsyringe";
@injectable()
@singleton()
export class Foo {
  constructor() {
    console.log("Constructor of Foo");
  }
}
  • Bar.ts(修改注入方式,直接用类)
import { injectable } from "tsyringe";
import { Foo } from "./Foo";
@injectable()
export class Bar {
  constructor(private foo: Foo) { // 直接注入Foo类,不需要@inject("Foo")
    console.log("Constructor of Bar");
  }
}
  • main.ts(移除Foo的手动注册)
import "reflect-metadata";
import { container } from "tsyringe";
import { Bar } from "./Bar";

// 不需要注册Foo,装饰器已经处理了
container.register("Bar", { useClass: Bar });

const instance = container.resolve(Bar);
const instance1 = container.resolve(Bar);

方案2:手动注册时指定单例生命周期

如果你确实需要用字符串令牌(比如有多个实现的情况),那注册的时候要显式指定生命周期为Singleton:

main.ts修改如下:

import "reflect-metadata";
import { container, Lifecycle } from "tsyringe";
import { Bar } from "./Bar";
import { Foo } from "./Foo";

// 注册Foo时指定生命周期为Singleton
container.register("Foo", { 
  useClass: Foo,
  lifecycle: Lifecycle.Singleton 
});
container.register("Bar", { useClass: Bar });

const instance = container.resolve(Bar);
const instance1 = container.resolve(Bar);

验证结果

不管用哪种方案,运行后都会得到你预期的输出:

Constructor of Foo
Constructor of Bar
Constructor of Bar

内容的提问来源于stack exchange,提问作者CyberProdigy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 12:34:05