Angular2依赖注入

曾自己借助阿里云和hexo搭了个站点,现已废弃,过往写的博客暂挪到此处。


title: Angular2依赖注入
subtitle: 小白学Angular2
date: 2016-11-24 22:53:51
tags:
- 技术
- Angular2
- 学习笔记


依赖注入用我这个小白的话说,就是定义一个类的时候,将某些依赖作为类的参数,即:

var myClass = function( arg1,arg2){
    this.arg1 = arg1;
    this.arg2 = arg2;
}

初始化该类的时候,就可以将这些依赖当做参数传递进去。
这样,当arg1和arg2改变的时候,我们可以不用动这个myClass内部的代码。

这个用法在纯js时代就常用,只是现在叫做依赖注入。目的是为了,解耦。

angular 依赖注入与 我的myClass的不同在于
如果arg1和arg2都是类的实例,
myClass需要先实例化这些类,然后再调用new myClass(instance1,instance2)。

而Angular,不需要先实例化每一个依赖注入的类。Angular自己会帮你实例化。但是需要以下几步
构造函数参数中有这些类: constructor(heroService:HeroService)
这个constructor的类有一个@Component装饰器(这个一般都不必说。。)
@Component中有这些类的providers信息,即providers:[HeroService]
对于被依赖的那些类,需要在export class之前加上@Injectable(),否则注入器会报错
注:服务是可以继承的

Angular中的显性注入器

首先这应当是没有必要的,只要正确使用依赖注入,angular自己会管理好注入器的创建和调用。
当方式如下:

  injector = ReflectiveInjector.resolveAndCreate([Car, Engine, Tires]);
  let car = injector.get(Car);

直接使用注入器Injector的方式

可以直接使用注入器工作,但不方便阅读,难以理解,所以尽量避免:
在@Component中添加这些类的providers信息,即providers:[HeroService]
在constructor中注入Injector(Injector本身就是一个可注入的服务)
然后在Component中通过injector.get方式获得providers提供的服务(即类HeroService)
如果get失败会抛出异常,get方法可以带第二个参数,表示如果服务没找到就当做默认值返回。

注入器的提供商们:

令牌token:它作为键值key使用,用于定位依赖值,以及注册这个提供商
providers: [Logger]
provider definition object:知道如何创建依赖值得配方,有很多方式创建依赖值

[{ provide: Logger, useClass: Logger }]
1. 备选的类提供商
[{ provide: Logger, useClass: BetterLogger }]

当请求Logger时,提供BetterLogger
(不同于别名,见3)

2. 带依赖的类提供商
[ UserService,
  { provide: Logger, useClass: EvenBetterLogger }]

因为EvenBetterLogger注入了UserService(??可是为什么不会在EvenBetterLogger中自动调用??还要在调用EvenBetterLogger的地方在provide声明一下这个服务。)

3. 别名类提供商
[ NewLogger,
  // Alias OldLogger w/ reference to NewLogger
  { provide: OldLogger, useExisting: NewLogger}]

对比1,1会创建两个实例,(??1在什么时候回用到??需要创建两个实例)

[ NewLogger,
  // Not aliased! Creates two instances of `NewLogger`
  { provide: OldLogger, useClass: NewLogger}]
4. 值提供商
[{ provide: Logger, useValue: silentLogger }]

silentLogger是一个对象

5. 工厂提供商

在需要动态创建依赖值得情况下,使用此方式

//deps为该服务需要的依赖,通过注入器传入工厂方法
export let heroServiceProvider =
  { provide: HeroService,
    useFactory: heroServiceFactory,
    deps: [Logger, UserService]
  };
let heroServiceFactory = (logger: Logger, userService: UserService) => {
  return new HeroService(logger, userService.user.isAuthorized);
};
//满足的场景
constructor(
  private logger: Logger,
  private isAuthorized: boolean) { }

getHeroes() {
  let auth = this.isAuthorized ? 'authorized ' : 'unauthorized';
  this.logger.log(`Getting heroes for ${auth} user.`);
  return HEROES.filter(hero => this.isAuthorized || !hero.isSecret);
}

注:我们为了重复利用导出一个变量捕获了这个工厂提供商:heroServiceProvider。但也可以不用导出再使用,直接在需要该服务的地方的provider里加上即可,同1、2、3、4
依赖注入令牌
注入器维护一个内部的令牌-提供商映射表。
对于类而言,类名就是这个令牌。
非类依赖

export interface AppConfig {
  apiEndpoint: string;
  title: string;
}

export const HERO_DI_CONFIG: AppConfig = {
  apiEndpoint: 'api.heroes.com',
  title: 'Dependency Injection'
};

TypeScript接口不是一个有效的令牌。
Angular不支持。
解释为:在强类型语言中接口是首选的用于查找依赖的主键,再使用依赖注入很奇怪。
TS在生成JS之后,不会再有接口。
Opaque Token
解决方案是使用一个Opaque Token(不透明的令牌)

import { OpaqueToken } from '@angular/core';

export let APP_CONFIG = new OpaqueToken('app.config');

使用OpaqueToken对象注册依赖的提供商

providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]

在@Inject的帮助,将这个配置对象注入到需要的构造函数中

constructor(@Inject(APP_CONFIG) config: AppConfig) {
  this.title = config.title;
}

可选依赖

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

constructor(@Optional() private logger: Logger) {
  if (this.logger) {
    this.logger.log(some_message);
  }
}

注:当使用@Optional()的时候,需要为空值做准备

进阶:

多级依赖注入器
angular的多级依赖注入系统支持与组件树并行的嵌套式注入器
大白话,子组件通过冒泡的方式向上查找需要的服务;
其次,每个注入器都会把它提供的服务处理成单例,但当我们并不想共享,想为单个组件生成一个实例,则不要把服务注入到父级的以及父级的父级的组件中。

其他规范:

建议为每个服务类都添加@Injectable(),无论是否被依赖,出于为了以后可能被依赖着想以及一致性

@Component和@Directive @Pipe都是InjectableMetadata的子类型,所以没有必要为component添加@Injectable方法

注入器可以从编译后的Javascript代码中读取类的元数据,并使用构造函数的参数类型信息来决定注入什么。
(不是每个JavaScript类都有元数据。TS编辑器默认忽视元数据。如果tsconfig.json中的emitDecoratorMetadata编译器选项为true,编译器就会在生成的Javascript中为每个至少拥有一个装饰器的类添加元数据。
注入器使用一个类的构造元数据来决定依赖类型(??依赖类型有些什么??),该构造元数据就是构造函数的参数类型所标识的。TS为任何带有一个装饰器的类生成这样的元数据,任何装饰器都生成。当然,使用一个合适的Injectable装饰器来标识更有意义。

你可能感兴趣的:(Angular2依赖注入)