Angular 依赖注入工作原理

依赖注入是一种设计模式,在很多编程语言中都可以看到,如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:应用会搜索所有上级模块的注入器,包括应用的根注入器。如果找到了匹配的依赖,停止搜索,创建依赖的对象实例,返回给消费者组件。如果没有找到匹配的依赖,则返回一个错误。

搜索过程如图所示:

注入器搜索结构
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 一、什么是依赖注入 控制反转(IoC) 控制反转的概念最早在2004年由Martin Fowler提出,是针对面向...
    Keriy阅读 3,177评论 0 8
  • 学习资料来自 Angular.cn 与 Angular.io。 本章在线例子 依赖注入 (Dependency i...
    小镭Ra阅读 1,462评论 0 2
  • 1. 组件通讯 1.1 向组件内部传递数据 注意:在属性的外面加 [] 表示绑定动态值,在组件内接收后是布尔类...
    浅忆_0810阅读 354评论 0 1
  • 曾自己借助阿里云和hexo搭了个站点,现已废弃,过往写的博客暂挪到此处。 title: Angular2依赖注入s...
    monvhh阅读 259评论 0 0
  • 依赖注入(DI -- Dependency Injection)是一种重要的应用设计模式。Angular里面...
    tuacy阅读 13,236评论 4 16