You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular DI:如何让组件使用自身模块的同名注入令牌提供者?

Angular依赖注入(DI)模块级提供者覆盖问题解决方案

问题原因

Angular中非懒加载模块的providers会被合并到根注入器。当Module1导入Module2时,两个模块的提供者都会被添加到根注入器,同名的InjectionToken会被后注册的提供者覆盖(此处Module1的提供者覆盖了Module2的)。Cmp2的注入器会向上查找根注入器,因此拿到的是Module1的配置。

解决方案

方案1:将Module2改为懒加载模块

懒加载模块会创建独立的注入器,其提供者不会与根注入器合并,模块内的组件会优先从自身模块的注入器获取依赖。

修改Module1的导入方式,通过路由懒加载实现:

// Module1的NgModule配置
@NgModule({
  imports: [
    RouterModule.forChild([
      { path: 'cmp2', loadChildren: () => import('./module2').then(m => m.Module2) }
    ])
  ],
  declarations: [Cmp1],
  providers: [
    {
      provide: PERMISSION_SERVICE,
      useFactory: () => ({ service: "service1" })
    }
  ]
})
export class Module1 {}

当访问对应路由加载Module2时,Cmp2会获取到Module2中定义的PERMISSION_SERVICE。

方案2:封装组件级提供者(推荐,无需修改模块加载方式)

将提供者封装为可复用常量,避免逐个组件重复配置:

首先在Module2中定义复用的提供者数组:

// module2.ts
export const MODULE2_PERMISSION_PROVIDERS = [
  {
    provide: PERMISSION_SERVICE,
    useFactory: () => ({ service: "service2" })
  }
];

然后在Module2的所有组件中引用该数组:

@Component({
  selector: 'cmp2',
  template: "CMP2",
  providers: [MODULE2_PERMISSION_PROVIDERS]
})
export class Cmp2 {
  constructor(@Inject(PERMISSION_SERVICE) private permissionService: any) {
    console.log('cmp2 ' + permissionService.service); // 输出`cmp2 service2`
  }
}

这种方式通过组件自身的注入器隔离依赖,不受根注入器影响,同时保持代码复用性。

方案3:配合@Self()装饰器明确查找范围

如果组件已定义自身提供者,使用@Self()强制从组件注入器获取依赖,避免向上查找:

@Component({
  selector: 'cmp2',
  template: "CMP2",
  providers: [MODULE2_PERMISSION_PROVIDERS]
})
export class Cmp2 {
  constructor(
    @Self() @Inject(PERMISSION_SERVICE) private permissionService: any
  ) {
    console.log('cmp2 ' + permissionService.service);
  }
}

内容的提问来源于stack exchange,提问作者Irdis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:32:10