Angular 依赖注入

问题描述

初学Angular,可能对一堆注解有些懵。typescript

咱们一块儿经过实例来探讨Angular的依赖注入。bootstrap

一路尝试

@Injectable

一个命令建的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去构造TestServiceapp

clipboard.png

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

clipboard.png

无效,仍然报错。发现只交给Angular托管是不行的,咱们还须要声明提供器。函数

提供器

须要提供器告诉Angular如何注入相关对象。学习

@NgModule({
    declarations: [],
    imports: [],
    providers: [TestService],
    bootstrap: [AppComponent]
})
export class AppModule {
}

clipboard.png

AppModuleproviders数组中声明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模块中,注入的TestServiceTestService类实例化的。

可是具体到组件,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中同样,若是循环依赖了怎么解决呢?

clipboard.png

@Injectable({
    providedIn: 'root'
})
export class StockService {

    constructor(private testService: TestService) {
    }
}
@Injectable({
    providedIn: 'root'
})
export class TestService {

    constructor(private stockService: StockService) {
    }
}

clipboard.png

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!

相关文章
相关标签/搜索