如何为Angular泛型服务的不同实例注入独立配置?
问题
我有一个泛型数据服务,其配置注入方式如下:
export default class GenericDataService<T> implements IGenericDataService<T> { constructor(private readonly httpClient: HttpClient, private readonly config: GenericDataServiceConfig ) { }
GenericDataServiceConfig包含baseUrl、endpoint等配置项。
该数据服务被注入到一个共享查找组件中:
export class GenericLookUpComponent<T> implements OnInit { constructor(private readonly dataService: GenericDataService<T>) {} ... }
同时,该服务也被注入到一个包含GenericLookupComponent的组件中:
export class LookupDemoComponent implements OnInit { constructor(private readonly nominalService: GenericDataService<Nominal>) { } ... }
现在我需要两个GenericDataService实例,分别用于共享查找组件和演示组件,且它们需要不同的配置。我尝试在组件的providers中注入配置:
@Component({ selector: 'app-lookup-demo', templateUrl: './lookup-demo.component.html', providers: [ GenericDataService, { provide: GenericDataServiceConfig, useValue: nominalConfig } ] })
但这样两个服务实例会获取到相同的配置,请问该如何为不同的服务实例指定不同的配置?
解决方案
方法一:自定义注入令牌区分实例
Angular依赖注入基于令牌匹配,默认类本身就是令牌,所以要区分不同的GenericDataService实例,需要为每个实例创建独立的令牌,并绑定对应配置。
- 定义注入令牌
import { InjectionToken } from '@angular/core'; import { GenericDataService } from './generic-data.service'; // 共享查找组件专属服务令牌 export const LOOKUP_DATA_SERVICE = new InjectionToken<GenericDataService<any>>('LOOKUP_DATA_SERVICE'); // 演示组件专属服务令牌 export const NOMINAL_DATA_SERVICE = new InjectionToken<GenericDataService<Nominal>>('NOMINAL_DATA_SERVICE');
- 配置服务实例与对应配置
在LookupDemoComponent的providers中,通过工厂函数创建服务实例并绑定配置:
import { LOOKUP_DATA_SERVICE, NOMINAL_DATA_SERVICE } from './tokens'; import { lookupConfig, nominalConfig } from './configs'; @Component({ selector: 'app-lookup-demo', templateUrl: './lookup-demo.component.html', providers: [ // 共享查找组件的服务实例 + 专属配置 { provide: LOOKUP_DATA_SERVICE, useFactory: (http: HttpClient) => new GenericDataService(http, lookupConfig), deps: [HttpClient] // 声明依赖的HttpClient }, // 演示组件的服务实例 + 专属配置 { provide: NOMINAL_DATA_SERVICE, useFactory: (http: HttpClient) => new GenericDataService(http, nominalConfig), deps: [HttpClient] } ] }) export class LookupDemoComponent implements OnInit { // 通过令牌注入演示组件的服务 constructor(@Inject(NOMINAL_DATA_SERVICE) private readonly nominalService: GenericDataService<Nominal>) { } ... }
- 修改共享组件的注入方式
import { LOOKUP_DATA_SERVICE } from './tokens'; export class GenericLookUpComponent<T> implements OnInit { // 通过令牌注入共享组件的服务 constructor(@Inject(LOOKUP_DATA_SERVICE) private readonly dataService: GenericDataService<T>) {} ... }
方法二:组件层级独立配置
利用Angular的DI层级特性,在GenericLookUpComponent自身的providers中配置专属服务和配置,这样它的服务实例会优先使用自身层级的配置,父组件的服务则使用父层级配置。
- 配置共享查找组件的专属依赖
@Component({ selector: 'app-generic-lookup', templateUrl: './generic-lookup.component.html', providers: [ GenericDataService, { provide: GenericDataServiceConfig, useValue: lookupConfig } // 共享组件专属配置 ] }) export class GenericLookUpComponent<T> implements OnInit { constructor(private readonly dataService: GenericDataService<T>) {} ... }
- 配置演示组件的专属依赖
@Component({ selector: 'app-lookup-demo', templateUrl: './lookup-demo.component.html', providers: [ GenericDataService, { provide: GenericDataServiceConfig, useValue: nominalConfig } // 演示组件专属配置 ] }) export class LookupDemoComponent implements OnInit { constructor(private readonly nominalService: GenericDataService<Nominal>) { } ... }
这种方式无需额外定义令牌,适合场景简单的情况,Angular会自动从当前组件层级查找依赖,找不到才向上级遍历。
方法三:泛型令牌工厂(灵活扩展)
如果需要支持大量不同泛型类型的服务实例,可以创建一个泛型令牌工厂,避免重复创建令牌:
import { InjectionToken } from '@angular/core'; // 泛型令牌工厂函数 export function createDataServiceToken<T>(tokenName: string) { return new InjectionToken<GenericDataService<T>>(tokenName); } // 为不同场景创建令牌 export const LOOKUP_DATA_SERVICE = createDataServiceToken<any>('LOOKUP_DATA_SERVICE'); export const NOMINAL_DATA_SERVICE = createDataServiceToken<Nominal>('NOMINAL_DATA_SERVICE');
后续的配置和注入方式与方法一完全一致,适合需要频繁扩展不同泛型服务的场景。
内容的提问来源于stack exchange,提问作者atamata
相关产品推荐
相关产品推荐

