依赖注入(Dependency injection),简称DI,是Angular中的基本概念之一。DI被连接到Angular框架中并允许Angular中作为装饰器的类(如组件,指令,管道或可注入对象)配置他们所需的依赖。
DI系统中存在两个主要的角色:依赖者与依赖消费者和依赖提供者。
Angular通过抽象方法的调用来促使依赖消费者与依赖提供者之间进行交互。但一个依赖被请求使用,注入器会检查这个依赖在注册仓库中是否存在一个有效的实例对象。如果未实例化,则创建该依赖的实例并存储在注册仓库中。Angular在应用运行过程中创建应用层的注入器(及root及注册器)。大部分场景下你不需要手动创建注入器,但你需要知道存在一个注入器层来连接依赖提供者与依赖消费者。
本主题主要涵盖了类如何作为一个依赖进行使用的基本场景。Angular同样允许我们将方法、对象、基础类型(string或Boolean)或其他类型作为依赖进行使用。了解更多信息,查看 依赖提供者 内容。
提供依赖
考虑一个名为 HeroService 类在组中间中作为依赖项
第一步是添加一个 @Injectable 装饰器,表示该类可以被注入
@Injectable()
class HeroService{}
下一步是将它提供出去使其在DI系统中可用。一个依赖可在多个地方被提供出去:
- 在应用的root级别使用provideIn
- 在组件级别
- 在应用的root级别使用ApplicationConfig
- 基于NgModule的应用程序
在应用的root级别使用 providedIn
providedIn可以将一个服务在应用root级别注入到其他类中被使用,并 在应用root级别提供一个服务,将服务注入到其他类中,并启用Angualr和Javascript代码优化器,让它们能有效的识别并移除未被使用的服务(通常被称为tree-shaking)。
通过@Injectable providedIn:'root' 将服务提供出去
@Injectable({
providedIn: 'root'
})
class HeroService{}
当你root级别提供一个服务HereService,Angular会创建一个单例,被共享的实例并将其注入到任何被请求的地方。
在组件级别
你能通过装饰器字段提供组件级别的服务,在这种情况下该组件下的所有实例以及组件内的其他组件和指令都能使用该服务。
@Component({
selectro: 'hero-list',
template: '...',
providers: [HeroService]
})
class HeroListComponent{}
当我们在组件级别注册了一个提供器,我们就可以在组件的每个实例上都获取到该服务的一个实例。
使用ApplicationConfig在应用root级注册
我们可以使用ApplicationConfig字段在每个应用级去提供一个服务。在下面这个例子中,HeroService服务在所有组件,指令,管道中都有效
export const appConfig: ApplicationConfig = {
providers: [
{provide: HeroService}
}
然后在 main.ts中使用
bootstrapApplication(AppComponent, appConfig)
注意:这种方式声明的服务将始终包含在你的应用中,尽管这个服务没有被使用。
注入/消费依赖
使用Angular中的 inject 方法去接收一个依赖
import {inject, Component} from 'angular/core'
@Component({/* ... */})
export class UserProfile {
// 属性初始化时使用inject方法
private userClient = inject(UserClient);
constructor() {
// 也可以在constructor中使用 inject方法
const logger = inject(Logger);
}
}
我们可以在任何可注入的上下文中使用 inject方法。我们时长在一个类中去初始化属性或者类的构造方法中使用。
当Angular发现一个组件依赖某个服务时,它实现会检查注入器中是否包含该服务的实例,如果该依赖的服务还不存在对象实例。注入器将会实例化该服务,并在返回给Angular之前先添加到注入器中。
当所有的服务请求都被解析并返回时,Angular将会调用组件的构造方法并将这些服务作为构造方法的参数注入。