NestJS中注入的Web3实例跨服务共享如何配置独立实例
NestJS 多服务注入独立Web3实例配置方案
问题原因
你当前配置出现实例共享的核心原因有两个:
- NestJS默认所有provider都是单例作用域,整个应用生命周期内同一个注入令牌(这里是
Web3类)只会对应一个实例,所有依赖该令牌的服务都会拿到同一个实例 - 你使用了
useValue写法注册Web3:useValue是直接将你提前创建好的new Web3()实例交给Nest容器管理,容器不会再生成新实例,无论怎么调整作用域都只会返回这一个固定对象。
可行解决方案
方案1:自定义专属注入令牌(推荐,粒度最可控)
不要让两个服务共用同一个Web3注入令牌,给每个服务单独定义专属的注入令牌,每个令牌对应独立的Web3实例,这种方式不需要修改服务默认作用域,性能最优。
- 先定义两个专属注入常量:
// 可以放在模块的constants文件里 export const ETH_WEB3 = Symbol('ETHEREUM_WEB3'); export const BSC_WEB3 = Symbol('BINANCE_WEB3');
- 修改模块的providers配置,为每个令牌单独注册实例:
@Module({ imports: [ConfigModule.forRoot(), HelperModule], providers: [ NEtheriumChainService, NBinanceChainService, NBitcoinChainService, NChainServiceProvider, { provide: ETH_WEB3, useFactory: () => new Web3(), }, { provide: BSC_WEB3, useFactory: () => new Web3(), }, ], exports: [NChainServiceProvider], }) export class NChainsModule {}
- 在对应服务的构造函数中,用
@Inject()指定要注入的专属令牌:
// NEtheriumChainService 中 @Injectable() export class NEtheriumChainService { constructor( @Inject(ETH_WEB3) private readonly web3: Web3 ) {} } // NBinanceChainService 中 @Injectable() export class NBinanceChainService { constructor( @Inject(BSC_WEB3) private readonly web3: Web3 ) {} }
这种方式下两个服务拿到的Web3实例完全独立,且实例只在模块初始化时创建一次,不会产生额外的性能开销,后续如果需要给其他链服务配置独立Web3实例,只需要新增对应令牌和provider即可。
方案2:设置Web3为瞬态作用域
如果你不想自定义注入令牌,可以把Web3 provider的作用域设置为TRANSIENT(瞬态),瞬态作用域的provider会在每个消费它的服务初始化时,单独创建一个新实例。
注意必须把useValue换成useFactory,否则作用域配置不生效:
import { Scope } from '@nestjs/common'; @Module({ imports: [ConfigModule.forRoot(), HelperModule], providers: [ NEtheriumChainService, NBinanceChainService, NBitcoinChainService, NChainServiceProvider, { provide: Web3, useFactory: () => new Web3(), scope: Scope.TRANSIENT, }, ], exports: [NChainServiceProvider], }) export class NChainsModule {}
这种写法不需要修改服务内的注入代码,直接在构造函数注入Web3即可。但要注意:后续所有注入Web3的服务都会拿到全新的独立实例,如果需要部分服务共享Web3实例,这种方式无法做到细粒度控制。
注意:不要使用
Scope.REQUEST作用域,该作用域会在每一次请求进入时都创建新的Web3实例,会产生不必要的性能损耗,不符合服务持有固定独立实例的需求。
内容的提问来源于stack exchange,提问作者vipes
相关产品推荐
相关产品推荐

