Angular组件级别注册Provider:为何案例2无法匹配案例1逻辑?
背景说明
当在组件级别注册Provider时,每个组件实例都会对应一个新的服务实例,该服务是组件的依赖,可通过构造函数注入由Angular框架管理,伪代码逻辑如下:
class Component { private Service service; constructor(Service service) { this.service = service; } }
组件实例创建时,Angular会自动将服务实例注入到组件构造函数中(类似手动编写HeroList hl = new HeroList(new HeroService())的效果)。
两个对比案例
1) 可正常运行的案例
hero.service.ts
import { Injectable } from '@angular/core'; @Injectable() export class HeroService { constructor() { } }
hero-list.component.ts
import { Component } from '@angular/core'; import { HeroService } from '../hero.service'; @Component({ selector: 'app-hero-list', templateUrl: './hero-list.component.html', styleUrls: ['./hero-list.component.css'], providers: [ HeroService ] }) export class HeroListComponent { constructor( private service: HeroService ) { } }
2) 无法实现案例1效果的案例
hero.service.ts
export class HeroService { constructor() { } }
hero-list.component.ts
import { Component } from '@angular/core'; import { HeroService } from '../hero.service'; @Component({ selector: 'app-hero-list', templateUrl: './hero-list.component.html', styleUrls: ['./hero-list.component.css'], }) export class HeroListComponent { constructor( private service: HeroService ) { } }
另外,若修改HeroListComponent为以下代码,也能实现每个组件实例对应新服务实例(属于手动组合模式):
export class HeroListComponent { private service: HeroService; constructor( ) { this.service = new HeroService(); } }
问题:为何案例2的代码无法实现案例1的组件级别服务注入效果?
原因解析
案例2达不到预期效果,是因为完全不符合Angular依赖注入(DI)的核心规则:
服务未标记为可注入对象
Angular的DI容器只会处理带有@Injectable()装饰器的类。案例2的HeroService没有添加该装饰器,Angular无法识别它是一个需要由DI系统管理的服务,自然无法自动创建并注入实例。组件未注册服务提供者
案例1的组件元数据中配置了providers: [HeroService],这明确告诉Angular:为该组件的每个实例单独创建一个HeroService实例,实现组件级别的实例隔离。而案例2的组件没有配置providers,Angular既不知道要注入这个服务,也没有规则去创建对应的实例。
补充:手动在构造函数中
new HeroService()的写法,虽然能实现每个组件对应新服务,但这是手动实例化,不属于Angular DI机制。这种写法会让组件与服务强耦合,无法利用DI带来的依赖替换、测试Mock等优势,和案例1的DI注入逻辑本质不同。
内容的提问来源于stack exchange,提问作者Murmulodi

