初学Angular
,可能对一堆注解有些懵。typescript
咱们一块儿经过实例来探讨Angular
的依赖注入。bootstrap
一个命令建的StockService
,一个手动建的TestService
。数组
@Injectable({ providedIn: 'root' }) export class StockService { constructor(private testService: TestService) { } }
export class TestService { constructor() { } }
TestService
未加@Injectable
注解,只是一个普通的TypeScript
类。promise
当前台组件中用到StockService
时,Angular
为咱们构造StockService
,构造函数中依赖TestService
,而后Angular
去构造TestService
。app
Uncaught (in promise): Error: StaticInjectorError(AppModule)[TestService]: StaticInjectorError(Platform: core)[TestService]: NullInjectorError: No provider for TestService!
而后发现控制台报错,没法提供TestService
,由于它没有被Angular
管理。dom
import {Injectable} from '@angular/core'; @Injectable() export class TestService { constructor() { } }
加上@Injectable
,将该类交给Augular
管理。ide
无效,仍然报错。发现只交给Angular
托管是不行的,咱们还须要声明提供器。函数
须要提供器告诉Angular
如何注入相关对象。学习
@NgModule({ declarations: [], imports: [], providers: [TestService], bootstrap: [AppComponent] }) export class AppModule { }
在AppModule
的providers
数组中声明TestService
提供器。优化
按类型提供,因此上面的声明与下面的代码是等价的。
providers: [{ provide: TestService, useClass: TestService }]
标记在AppModule
上,表示该TestService
的注入是应用在该模块上的。在该模块中,TestService
是单例的。
{ provide: TestService, useClass: TestService }
,表示当须要注入TestService
类型的对象时,使用TestService
类构造出的对象进行注入。
Angular
中,为何@Component
、@Pipe
里能用构造函数注入@Injectable
呢?答案与Spring
一致,为何@Controller
、@Service
里能Autowired
呢?思想相同。
@NgModule({ providers: [TestService] }) export class AppModule { } @Component({ providers: [{ provide: TestService, useClass: AnotherTestService }] }) export class StockComponent { constructor(private testService: TestService) { } }
声明一个模块级的与一个组件级的提供器,表示在本模块或本组件中应该注入什么。
就像如上代码,声明在整个AppModule
模块中,注入的TestService
是TestService
类实例化的。
可是具体到组件,StockComponent
,虽然声明整个模块都使用TestService
,可是有时不符合需求,因此在此组件中使用AnotherTestService
注入。
就像Spring
中的@Primary
与@Qualifier
同样。
经过useValue
的值提供,能够定义一些常量,又是枚举的思想,咱们使用引用,而不是用常量。
{ provide: domain, useValue: 'www.mengyunzhi.com' }
除了值提供还有工厂方法,当Angular
默认的实例化对象没法知足咱们的要求时,咱们要写本身的工厂函数生成咱们的对象实例。
可是注意:虽然该方法叫工厂方法,可是该方法只在第一次用到该对象时执行一次,之后再须要用的仍是以前构造出来的对象。
虽然叫工厂方法,可是仍是单例的。
{ provide: ProductService, useFactory: () => { 返回一个对象实例 } }
如今若是用ng
生成的Angular
服务,标准的写法是providedIn: 'root'
。
粗略学习了一下,摇树优化就是按需加载,减少咱们的包体积,缩短应用的加载时间。
@Injectable({ providedIn: 'root' })
只要在服务自己的@Injectable()
装饰器中指定,而不是在依赖该服务的NgModule
或组件的元数据中指定,你就能够制做一个可摇树优化的提供商。
要想覆盖可摇树优化的提供商,请使用其它提供商来配置指定的NgModule
或组件的注入器,只要使用@NgModule()
或@Component()
装饰器中的providers: []
数组就能够了。
经过上面的学习,咱们知道了Angular
中的依赖注入是经过构造函数的参数注入来实现的。
可是只要是经过构造函数实现的IOC
容器就会有问题,就像Spring
中同样,若是循环依赖了怎么解决呢?
@Injectable({ providedIn: 'root' }) export class StockService { constructor(private testService: TestService) { } }
@Injectable({ providedIn: 'root' }) export class TestService { constructor(private stockService: StockService) { } }
Circular dependency detected: src/app/service/stock.service.ts -> src/app/service/test.service.ts -> src/app/service/stock.service.ts Circular dependency detected: src/app/service/test.service.ts -> src/app/service/stock.service.ts -> src/app/service/test.service.ts
与Spring
同样,若是循环了,由于是使用构造函数注入,因此一个对象都构造不出来,没法解决。开发时应避免循环依赖。
万物相通。
Hello, Angular!