Dependence Injection(依赖注入)

dependency-injection-in-angular-2

依赖注入是Angular中的最大的一个特性与卖点。它允许应用中不同的组件不需要显性地建立关联即可以相互调用。不同,Angular 1中的依赖注入仍然是存在着一些问题,这也是Angular 2完全重构了一套依赖注入系统的原因。Angular 1中的依赖注入系统主要存在的问题如下:

  • Internal Cache(内建缓存):依赖一般是被当做单例对待,任何一个服务在整个应用的生命周期中都应该只被创建一次。

  • Synchronous by default(默认异步):Angular 1中的服务创建不是异步创建的。

  • Namespace collision(命名空间冲突):在应用的生命周期中某个”type”的token是唯一的,如果我们自定义了一个名为Car的服务,而引入的第三方框架中也存在着同名的Car的服务,那么整个系统就会存在问题。

  • Built into the framework(框架内建):Angular 1的依赖注入是内建的,我们无法单独的进行使用。

Angular 2的依赖注入体系大概如下所示:

其中有几个关键的概念解释如下:

  • Injector(注入器):Injector就类似于Spring里面的ApplicationContext,提供了一系列的接口以供依赖实例的创建。

  • Binding(绑定):Binding的作用在于告诉Injector如何去为某个依赖创建实例。一个Binding需要映射到一个工厂类型的方法。

  • Dependence(依赖):一个Dependence是某个对象被创建的类型。

最简单的Angular 2中的依赖注入的方式如下:

import { Injector } from 'angular2/di';var injector = Injector.resolveAndCreate([Car,Engine,Tires,Doors
]);var car = injector.get(Car);

resolveAndCreate是一个静态的接口方法,根据输入的一系列的Binding来创建依赖的实例。而后,可以使用injector.get()方法来获取某个Type/Token对应的对象实例。而在使用这个依赖时,可以使用Angular 2内置的Inject:

import { Inject } from 'angular2/di';class Car {constructor(@Inject(Engine) engine,@Inject(Tires) tires,@Inject(Doors) doors) {...}
}

Inject装饰器会自动将元数据绑定到Car类的属性中,也可以改写为TypeScript的方式:

class Car {constructor(engine: Engine, tires: Tires, doors: Doors) {...}
}

到这一步,某个类可以声明它自己的依赖,并且被DI解析所有该类的依赖项。但是Injector还需要从Binding中获取如何去创建这些对象实例的信息。上文中是直接在resolveAndCreate方法中传入了一系列的Type/Token,而如果使用完整的写法,应该使用toClass方法显性的将某个Type/Token映射到某个实例。

import { bind } from 'angular2/di';var injector = Injector.resolveAndCreate([bind(Car).toClass(Car),bind(Engine).toClass(Engine),bind(Tires).toClass(Tires),bind(Doors).toClass(Doors)
]);

上述方法中的token可以是任意的类型或者一个字符串,这也就是所谓的Recipe机制的具体实现。在这样的一种Binding的帮助下,不仅仅Injector知道如何在应用过程中使用这些依赖,并且配置了如何创建这些依赖。

进一步考虑,如果在应用中已经确定了Foo类型,那又何必要写bind(Foo).toClass(Foo)这样的表达式,直接在程序中引入写死即可,而依赖注入的真正魅力在于:

bind(Engine).toClass(OtherEngine)

这样可以动态的为某个token绑定到依赖中,并且有效解决了命名空间冲突的问题。我们可以创建一个类似与接口的类型,然后将它指向到具体的类型中。就像Java中的Interface与Implementation。

Other binding instructions

有时候,我们并不一定需要将某个token绑定到某个类中,而是绑定到某个字符串值或者工厂方法中。

  • 绑定到值

bind(String).toValue('Hello World')
  • 绑定到别名

bind(Engine).toClass(Engine)
bind(V8).toAlias(Engine)

toAlias方法将某个token绑定到另一个token中。

  • 绑定到某个工厂方法

bind(Engine).toFactory(() => {if (IS_V8) {return new V8Engine();} else {return new V6Engine();}
})

当然,某个工厂方法可能也有其依赖项,只要简单地将依赖项指向到参数中并且添加到token列表中即可。

bind(Engine).toFactory((dep1, dep2) => {if (IS_V8) {return new V8Engine();} else {return new V6Engine();}
}, [Token1, Token2])

Transient Dependencies and Child Injectors(短暂性传递与子注入器)

在上文中提及的依赖项往往都是单例化的,但是有时候我们需要的是一个短暂的,即非单例模式的依赖,总体来说有两种方式:

  • 使用工厂模式

bind(Engine).toFactory(() => {return new Engine();
})
  • 子注入器

可以使用Injector.resolveAndCreateChild()这个方法迭代地创建子注入器,一个子注入器会继承父类注入器中声明的依赖项,但是如果子注入器中也是声明了某个依赖,那么它创建的实例与父注入器创建的同样的token的实例是不一致的:

var injector = Injector.resolveAndCreate([Engine]);
var childInjector = injector.resolveAndCreateChild([Engine]);injector.get(Engine) !== childInjector.get(Engine);

Component Dependence

@Component({selector: 'app'
})
@View({template: '<h1>Hello !</h1>'
})
class App {constructor() {this.name = 'World';}
}bootstrap(App);

上述声明的Component是直接将name写死在了代码里,如果将获取名字的这部分提取出来作为一个单独的服务:

class NameService {constructor() {this.name = 'Pascal';}getName() {return this.name;}
}

如果需要使用NameService,那么在声明某个Component时候,就需要使用@Inject装饰器:

class App {constructor(@Inject(NameService) NameService) {this.name = NameService.getName();}
}

如果是TypeScript,需要这么写:

class App {constructor(NameService: NameService) {this.name = NameService.getName();}
}

而NameService的Injector以及Binding这一步,其实就是由bootstrap方法实现的:

bootstrap(App, [NameService]);

当然,也可以写的更加优雅:

@Component({selector: 'app',bindings: [NameService]
})
@View({template: '<h1>Hello !</h1>'
})
class App {...
}

前端之Angular2实战:依赖注入详解与应用相关推荐

  1. Spring 依赖注入详解

    一.IOC 依赖注入 1.什么是Spring的依赖注入 依赖注入,是IOC的一个方面,是个通常的概念,它有多种解释.这概念是说你不用创建对象,而只需要描述它如何被创建.你不在代码里直接组装你的组件和服 ...

  2. 控制反转与依赖注入详解

    文章目录 前言 关键代码 控制反转 DI的方式 构造函数注入 set注入 接口注入 Service Locator 简单例子 独立接口方式 动态ServiceLocator 模式选择 DI / Ser ...

  3. php 依赖注入的写法,php的依赖注入详解

    本篇文章讲述了PHP的依赖注入,对于php依赖注入不太了解的同学但是有点感兴趣的那么就更要看看本篇文章咯,废话不多说了,我们直接来看看php的依赖注入吧! 依赖注入 理解:是一种允许我们从硬编码的依赖 ...

  4. .net程序开发IOC控制反转和DI依赖注入详解

    大部分应用程序都是这样编写的:编译时依赖关系顺着运行时执行的方向流动,从而生成一个直接依赖项关系图. 也就是说,如果类 A 调用类 B 的方法,类 B 调用 C 类的方法,则在编译时,类 A 将取决于 ...

  5. python 依赖注入_Dependency Injection-依赖注入详解

    依赖注入是目前很多优秀框架都在使用的一个设计模式.Java的开发框架如Spring在用,PHP的Laravel/Phalcon/Symfony等也在用.好多不同语言的框架,设计思想大同小异,相互借鉴参 ...

  6. spring学习笔记03-spring-DI-依赖注入详解(通过xml配置文件来配置依赖注入)

    spring学习笔记03-spring-DI-依赖注入详解 1.概念 2.构造函数注入 3.set方法注入 4.集合的注入 需要被注入的实体对象 package com.itheima.service ...

  7. Spring 3.0 注解注入详解

    Spring 3.0 注解注入详解 2011-04-15 09:44 17ZOUGUO ITEYE博客 我要评论(1) 字号:T | T AD: 一.各种注解方式 1.@Autowired注解(不推荐 ...

  8. 网络安全学习--008--SQL注入之Access数据库注入详解

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Access注入漏洞详解 一:注入漏洞分析 站库分类: 1.网站分类: 静态网页: 不依赖数据库 灵活性差,制作.更新.维护麻烦 交互 ...

  9. 【Spring 工厂】注入详解 — Set注入(JDK内置类型,用户自定义类型)、构造注入(重载)

    Spring 注入(Injection) 什么是注入? 为什么要注入? 如何进行注入[开发步骤] Spring注入的原理分析(简易版) Set注入详解 JDK内置类型 String+8种基本类型 数组 ...

  10. Spring三级缓存解决循环依赖问题详解

    spring三级缓存解决循环依赖问题详解 前言 这段时间阅读了spring IOC部分的源码.在学习过程中,自己有遇到过很多很问题,在上网查阅资料的时候,发现很难找到一份比较全面的解答.现在自己刚学习 ...

最新文章

  1. 系统架构升级要不要上微服务?历“久”弥新微服务——你真的需要升级微服务架构吗
  2. jQuery中鲜为人知的的几个方法
  3. R语言plotly可视化:plotly可视化多个直方图、通过bingroup参数设置多个直方图使用相同的bins设置(Share bins between histograms)
  4. 51 执行远程命令(Paramiko)
  5. 简书显示服务器错误,openfire服务器异常处理
  6. 解决Windows安装TensorFlow报错:ERROR: Cannot uninstall 'wrapt'问题
  7. 2能不用cuda_cuda学习-1-cufft的使用
  8. 系统架构师笔记(2)
  9. 超越提升和迁移 充分利用云计算的七种方法
  10. 通过一个实际例子理解Kubernetes里pod的自动scale - 水平自动伸缩
  11. HTTP Status 500 - 问题
  12. 学习笔记:平衡树-splay
  13. 【自用】docker命令记录
  14. 禁止微信调整页面字体大小
  15. Tomcat如何配置X-Frame-Options头
  16. 人工智能ai算法_AI算法比您想象的要脆弱得多
  17. java设置本机地址写在哪个类_JAVA获取指定的类型的本机MAC地址
  18. 四阶行列式计算_通过考试01 / 行列式的计算
  19. 关于邮箱显示已经回复,但是已发送邮件里面没有
  20. android 修改充电图标,更换图标、修改充电音...这个软件把iPhone玩成了安卓

热门文章

  1. php 异步执行脚本,PHP语言实现脚本异步执行_PHP教程
  2. w10恢复出厂设置_Win10系统恢复出厂设置和重装系统有什么区别?
  3. jdk32位安装包下载_MySQL 8.0.19安装图文详解!手把手教会您从下载到安装成功
  4. linux 格式化ntfs u盘,手机u盘数据恢复linux格式化为ntfs格式
  5. 此工作簿已丢失了其VBA项目 Activex控件以及其他任何与可编程序性相关的功能...
  6. DockerCon 2017报告:企业在关注吗?
  7. Spring+Mybatis+SpringMVC后台与前台分页展示实例(附工程)(转)
  8. java.lang.IllegalArgumentException: addChild: Child name '/SSHE' is not unique
  9. AspNetPager分页控件样式
  10. vSphere 5.5.0 U1配置问题:主机的快速统计信息不是最新的