一、依赖注入
a) 如果模块A需要依赖模块B,通常的做法是在A中导入B,import{B} from ‘B’,但有一些场合需要解除这种直接依赖,比如单元测试时需要mock一个B对象、还有时要创建B的单例或者用工厂模式生成B,这时适合使用依赖注入(Dependency Injection)的方式来解除对B的直接依赖。
b) Angular的依赖注入框架包含三部分,Provider、Injector、Dependency,三者的关系为:
Provider的作用是建立类与其依赖项之间的映射(mapinding);Dependency为依赖项;Injector负责在创建对象的时候解析相关的依赖并根据Provider提供的绑定信息进行注入。
c) 记录用户登录信息的UserService是一个全局单例,对其注入并使用的例子为:
import{ Component, ReflectiveInjector } from '@angular/core';
import{ UserService } from '../services/user.service';
…
exportclass UserDemoComponent {
userName: string;
userService: UserService;
constructor() {
const injector: any =
ReflectiveInjector.resolveAndCreate([UserService]);
this.userService =injector.get(UserService);
}
signIn(): void {
this.userService.setUser({ name: 'Dante'});
this.userName =this.userService.getUser().name;
}
}
导入ReflectiveInjector类后,使用它的静态方法resolveAndCreate来创建一个injector,可被注入的内容以数组的形式从参数传入,injector.get(UserService)可以解析出一个UserService对象,这里将类本身作为token。
二、使用NgModule进行注入
a) 通过前面的代码可以直观地了解注入的过程,但实际使用中却不这样做,而是要在NgModule的providers中注册依赖项,然后通过装饰器在需要使用的类的构造函数中注入:
constructor(privateuserService: UserService) {}
需要注意的是,被注入的类要用@Injectable标记,而且这样是以单例的方式注入的,还有其它注入的形式,比如非单例类、注入一个值、调用方法并把方法的返回值注入等。
providers:[UserService]这样的写法默认会注入UserService的单例,这实际上是一种简化的写法,provider的完整配置代码应该为
providers: [{ provide: UserService, useClass: UserService }],
provide字段指明了注入时的token,通过userClassuseValue等则可以设置注入对象和注入方式。
b) 注入值
//配置
providers:[{ provide: 'API_URL', useValue: 'http://api.com/v1' }]
//使用
import{ Inject } from '@angular/core';
…
constructor(@Inject('API_URL')apiUrl: string) {}
使用的时候要用到@Inject标记,使用这种写法可以注入全局常量。
c) 调用方法
{provide: 'API_URL', useFactory() { return 'api.com'; }
使用useFactory来调用方法作为返回值,可以使用上面的写法,也可以使用lambda表达式的形式useFactory : ( )=>…
useFactory指向的方法的返回值将会被注入。
d) 如果调用的方法需要传入参数,可以使用第三个属性:deps,比如API_URL1要用到API_URL的值作为参数:
{provide: 'API_URL1', deps: ['API_URL'], useFactory(apiUrl: string) { returnapiUrl + 'api.com'; }
那么如果要注入非单例对象,也可以通过useFactory来实例化并返回了。