美文网首页收藏react & vue & angular
Angular 依赖注入工作原理

Angular 依赖注入工作原理

作者: 品品下午茶 | 来源:发表于2022-05-18 14:44 被阅读0次

依赖注入是一种设计模式,在很多编程语言中都可以看到,如Java,C#.

这里,我们要解释跟依赖注入有关的三个概念:

  • 依赖(dependency)
  • 注入(injection)
  • 注入器(injector)

在一个应用中,一个对象实例(消费者)会在其内部使用其他对象实例,完成业务逻辑。这些被使用的对象实例,称为依赖。把依赖传递给消费者代码的过程,称为注入。如果在注入过程中,借助了第三方代码,这些代码称为注入器注入者。使用注入器的原因,是因为消费者代码通常只知道依赖的接口,而对如何初始化一个依赖知之甚少。

依赖注入设计模式解决的主要问题是代码的耦合。例如,Angular 组件的职责是把数据渲染到页面上。那么如何获得数据呢?一种方法是,把需要的数据在组件类的代码中写好,也就是使用静态数据;另一种方法是把获得数据的业务逻辑委托给某个服务(依赖),在组件类的代码中,调用该服务,获得需要的数据。

第一个方法的明显缺陷就是违背了软件的单一职责的设计原则。下面,我们介绍如何使用依赖注入的设计模式,实现第二个方法。

创建数据服务

我们在前面的文章中,介绍了如何在组件模板展示一个图书列表。图书列表的数据是放置在主组件类(AppComponent)中的静态数据:

export class AppComponent {
…
  books: Book[] = [
    {id: 1, name: '《三体》', price: 50.00},
    {id: 2, name: '《黑暗森林》', price: 40.00},
    {id: 3, name: '《死神永生》', price: 60.00},
    {id: 4, name: '《超新星纪元》', price: 35.00}
  ];
…
}

现在,我们就创建一个服务,返回这些数据。

  1. 使用 Angular CLI 命令创建一个图书服务。在 src/app 路径下,运行下面的命令:
ng generate service books/book

命令输出:

CREATE src/app/books/book.service.spec.ts (347 bytes)
CREATE src/app/books/book.service.ts (133 bytes)

文件结构如下所示:

服务文件结构

服务类是一个普通的 TypeScript 类,附加了 @Injectable 装饰器。

import { Injectable } from '@angular/core’;

@Injectable({
  providedIn: ‘root’
})
export class BookService {

  constructor() { }
}

如果一个类附加了 @Injectable 装饰器,就表示是 Angular 的服务,并且可以注入到 Angular 的组件或其他服务中。

与组件一样,服务也必须进行注册,才能使用。@Injectable 装饰器的 providedIn 属性值是一个对象,表示服务的注入器。 上面代码中的 root,表示根注入器,也是默认注入器。

  1. 在 BookService 类中,创建一个方法,返回图书列表数据。
  getBooks(): Book[] {
    return [
      {id: 1, name: '《三体》', price: 50.00},
      {id: 2, name: '《黑暗森林》', price: 40.00},
      {id: 3, name: '《死神永生》', price: 60.00},
      {id: 4, name: '《超新星纪元》', price: 35.00}
    ];
  }

使用数据服务

BookService 已经可以为我们提供图书数据,下面就把这些图书展示到应用的首页上。

  1. BookListComponent 类中,声明 books 属性和 bookService 属性。
  books: Book[];
  private bookService: BookService;
  1. BookListComponent 类的构造函数中,创建 BookService 的一个实例对象,为 bookService 属性赋值。
  constructor() {
    this.bookService = new BookService();
  }
  1. BookListComponent 类的初始化方法中,获取图书数据。
  ngOnInit(): void {
    this.books = this.bookService.getBooks();
  }
  1. 修改 book-list.component.html 文件,展示图书列表数据。
<ul>
  <li *ngFor="let book of books">{{book.name}}</li>
</ul>
  1. 修改 app.component.html 文件,删除文件中的全部内容,只保留下面一行代码。
<app-book-list></app-book-list>
  1. 运行应用,打开浏览器,访问 http://localhost:4200/,页面显示如下:
    图书列表展示

注入数据服务

细心的你一定发现了上面代码中存在的问题。在 BookListComponent 类的构造函数中,我们手工创建了 BookService,并没有使用依赖注入设计模式。接下来,我们就对代码进行调整,使用 Angular 提供的依赖注入机制,把 BookService 注入到 BookListComponent 中。

  1. BookListComponent 类中,删除 bookService 属性。
  books: Book[];
  1. BookListComponent 类中,修改构造函数,把需要注入的服务,作为构造函数的参数传入。
constructor(private bookService: BookService) {}

现在,组件不需要再进行服务类的实例化工作。在初始化方法使用服务实例对象之前,已经在构造函数中对服务类进行了实例化。

依赖注入机制

在 Angular 应用中,除了根注入器,模块和组件都提供了注入器。注入器也按层次结构进行组织。当一个组件需要一个依赖时,应用会进行一个两阶段当搜索过程。

  • 阶段1:应用会搜索消费者组件的所有上级组件(直接的和间接的)。如果找到了匹配的依赖,停止搜索,创建依赖的对象实例,返回给消费者组件。如果没有找到匹配的依赖,则进行阶段2。
  • 阶段2:应用会搜索所有上级模块的注入器,包括应用的根注入器。如果找到了匹配的依赖,停止搜索,创建依赖的对象实例,返回给消费者组件。如果没有找到匹配的依赖,则返回一个错误。

搜索过程如图所示:

注入器搜索结构

相关文章

网友评论

    本文标题:Angular 依赖注入工作原理

    本文链接:https://www.haomeiwen.com/subject/akvourtx.html