Angular(4+)如何查找实现特定接口的所有服务提供者?
嘿,这个需求我之前在Angular项目里正好折腾过!其实Angular本身没法直接通过TypeScript接口去查询它的所有实现——因为接口在编译成JavaScript后就被完全擦除了,DI系统根本看不到它。不过我们可以用**注入令牌(InjectionToken)**来模拟这种“扩展点”机制,完美实现你要的运行时发现所有接口实现的效果,下面给你一步步说怎么做:
核心思路
Angular的依赖注入是基于“令牌”而非接口的,所以我们要先给你的SearchStrategy接口创建一个对应的令牌,然后让所有实现类都注册到这个令牌下。最后通过注入这个令牌对应的数组,就能拿到所有实现实例了。
具体实现步骤
1. 定义接口和注入令牌
首先把你的SearchStrategy接口和对应的令牌放在同一个文件里,方便管理:
// search-strategy.interface.ts import { InjectionToken, Observable } from '@angular/core'; export interface SearchStrategy { search(query: string): Observable<any[]>; // 加个类型标识,方便后续区分不同的策略 getStrategyType(): string; } // 创建一个注入令牌,用来标识所有SearchStrategy的实现 export const SEARCH_STRATEGIES = new InjectionToken<SearchStrategy[]>('SEARCH_STRATEGIES');
2. 实现具体的策略服务
接下来写你的两个实现类,记得加上@Injectable()装饰器:
// person-search.strategy.ts import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { SearchStrategy } from './search-strategy.interface'; @Injectable() export class PersonSearchStrategy implements SearchStrategy { search(query: string): Observable<any[]> { // 这里写你的人员搜索逻辑 return of([]); } getStrategyType(): string { return 'person'; } }
// document-search.strategy.ts import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { SearchStrategy } from './search-strategy.interface'; @Injectable() export class DocumentSearchStrategy implements SearchStrategy { search(query: string): Observable<any[]> { // 这里写你的文档搜索逻辑 return of([]); } getStrategyType(): string { return 'document'; } }
3. 在模块中注册所有策略
在你的NgModule(比如SearchModule)里,把这些策略服务注册到SEARCH_STRATEGIES令牌下,关键是要加上multi: true——这个配置告诉Angular:“这个令牌对应多个提供者,把它们都收集成数组”:
import { NgModule } from '@angular/core'; import { SEARCH_STRATEGIES } from './search-strategy.interface'; import { PersonSearchStrategy } from './person-search.strategy'; import { DocumentSearchStrategy } from './document-search.strategy'; @NgModule({ providers: [ { provide: SEARCH_STRATEGIES, useClass: PersonSearchStrategy, multi: true }, { provide: SEARCH_STRATEGIES, useClass: DocumentSearchStrategy, multi: true } ] }) export class SearchModule { }
4. 运行时获取所有策略实例
现在你就可以在任何需要的地方(比如组件或服务),通过注入SEARCH_STRATEGIES来拿到所有实现类的实例了:
import { Injectable, Inject } from '@angular/core'; import { SEARCH_STRATEGIES, SearchStrategy } from './search-strategy.interface'; import { Observable, forkJoin } from 'rxjs'; @Injectable() export class SearchService { constructor( // 注入所有SearchStrategy实例 @Inject(SEARCH_STRATEGIES) private readonly strategies: SearchStrategy[] ) {} // 用所有策略一起搜索 searchWithAll(query: string): Observable<any[][]> { const searchObservables = this.strategies.map(strategy => strategy.search(query)); return forkJoin(searchObservables); } // 根据类型获取特定策略 getStrategyByType(type: string): SearchStrategy | undefined { return this.strategies.find(strategy => strategy.getStrategyType() === type); } }
额外注意事项
- 懒加载插件的处理:如果你的策略在懒加载模块里,那只有当模块被加载后,对应的实例才会加入到数组里。如果需要应用启动时就加载所有插件,可以用
APP_INITIALIZER来预加载这些模块。 - 类型安全保障:虽然接口编译后会消失,但在TypeScript层面,我们依然可以通过接口来约束所有实现类的结构,确保编译时就能发现类型错误。
- 动态添加插件:如果需要动态添加插件(比如从后端加载),可以结合
Injector的provide方法,手动把新的策略实例添加到令牌对应的数组里。
内容的提问来源于stack exchange,提问作者Peter Walser
相关产品推荐
相关产品推荐

