如何在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
相关产品推荐
相关产品推荐

