Angular中单个注入令牌如何在运行时解析为多个不同服务
问题结论
你的需求完全可以在Angular运行时实现,首先需要纠正你现有配置的问题:同一注入层级下,对同一个InjectionToken多次配置提供者时,后声明的配置会覆盖之前的配置,因此你当前写的模块providers配置无法满足需求,默认所有注入ACCOUNT_SERVICE的位置只会拿到AccountServiceTwo实例。
可落地实现方案
方案1:服务级别配置独立提供者(最简洁,无侵入)
你可以直接在AccountServiceA和AccountServiceB的@Injectable装饰器中,分别配置当前服务注入上下文下的ACCOUNT_SERVICE实现,两个服务的配置互相隔离不会冲突:
@Injectable({ providedIn: 'root', // 仅当前服务注入时生效的提供者配置 providers: [ { provide: ACCOUNT_SERVICE, useClass: AccountServiceOne } ] }) export class AccountServiceA { public constructor( @Inject(ACCOUNT_SERVICE) private accountService: AccountServiceOne ) {} } @Injectable({ providedIn: 'root', // 仅当前服务注入时生效的提供者配置 providers: [ { provide: ACCOUNT_SERVICE, useClass: AccountServiceTwo } ] }) export class AccountServiceB { public constructor( @Inject(ACCOUNT_SERVICE) private accountService: AccountServiceTwo ) {} }
方案2:多提供者模式(适合动态判断场景)
如果你需要在全局配置所有实现,后续在注入位置自主选择对应实例,可以开启multi: true的多提供者配置,注入时会拿到该令牌对应的所有实例数组:
- 调整模块providers配置:
providers: [ { provide: ACCOUNT_SERVICE, useClass: AccountServiceOne, multi: true // 开启多提供者 }, { provide: ACCOUNT_SERVICE, useClass: AccountServiceTwo, multi: true } ]
- 服务注入时筛选需要的实例:
// 建议先为两个服务定义公共抽象父类,方便类型约束和实例判断 @Injectable({ providedIn: 'root' }) export class AccountServiceA { private accountService: AccountServiceOne; public constructor( @Inject(ACCOUNT_SERVICE) accountServices: Array<BaseAccountService> ) { // 也可以给每个实现类加唯一标识字段,比instanceof判断效率更高 this.accountService = accountServices.find(s => s instanceof AccountServiceOne) as AccountServiceOne; } } @Injectable({ providedIn: 'root' }) export class AccountServiceB { private accountService: AccountServiceTwo; public constructor( @Inject(ACCOUNT_SERVICE) accountServices: Array<BaseAccountService> ) { this.accountService = accountServices.find(s => s instanceof AccountServiceTwo) as AccountServiceTwo; } }
内容的提问来源于stack exchange,提问作者Madhur Maurya
相关产品推荐
相关产品推荐

