美文网首页
依赖注入

依赖注入

作者: oWSQo | 来源:发表于2019-07-13 08:58 被阅读0次

在依赖注入中,注入器是粘合剂,它连接了调用方和被依赖方。注入器根据Provider的配置来生成依赖对象,调用方根据Provider提供的标识告诉注入器来获取被依赖的对象。

  • 注入器(Injector):提供一系列的接口用于创建依赖对象的实例。
  • Provider:用于配置注入器,注入器通过它来创建被依赖对象的实例,Provider把标识(Token)映射到工厂方法,被依赖的对象就是通过该方法来创建的。
  • 依赖(Dependence):指定了被依赖对象的类型,注入器会根据此类型创建对应的对象。

在组件中注入服务

在组件中使用依赖注入需要三步:

  • 通过import导入被依赖对象的服务。
  • 在组件中配置注入器。在启动组件时,angular会读取@Component装饰器里的providers元数据,它是一个数组,配置了该组件需要使用到的所有依赖,angular的依赖注入框架会根据这个列表去创建对应对象的实例。
  • 在组件构造函数中声明需要注入的依赖。注入器会根据构造函数上的声明,在组件初始化时通过第二步中的providers元数据配置依赖,为构造函数提供对应的依赖服务,最终完成注入的过程。
//app.component.ts
import { Component } from '@angular/core';
//1.导入被依赖对象的服务
import { ContactService } from './shared/contact.service';
import { LoggerService } from './shared/logger.service';
import { UserService } from './shared/user.service';
@Component({
    moduleId:module.id,
    selector:'contact-app',
    //2.在组件中配置注入器
    providers[ContactService,LoggerService,UserService],
    templateUrl:'./app.component.html',
    styleUrls:['./app.component.css']
})
export class ContactAppComponent {
    //3.在组件构造函数中声明需要注入的依赖
    constructor(
        logger:LoggerService,
        contactService:ContactService,
        userService:UserService
    ) {}
}

在ContactAppComponent这个根组件中配置了providers元数据,这使得ContactAppComponent及其所有子组件,都能共享由根组件注入器创建的实例。CollectionComponent是ContactAppComponent的子组件,它并没有在@Component中添加providers元数据来注入ContactService服务,但依然可以在构造函数中获取到ContactService服务的实例。

//collection.component.ts
import { Component,OnInit } from '@angular/core';
import { ContactService } from './shanred/contact.service';
@Component({
    selector:'call-record',
    templateUrl:'./app/collection/collection.component.html',
    styleUrls:['./app/collection/collection.component.css']
})
export class CollectionComponent implements OnInit{
    collections:any=[];
    contacts:any={};
    constructor(private _contactService:ContactService) {}
}

在服务中注入服务

除了组件依赖服务,服务间的相互调用也很常见。

//contact.service.ts
import { Injectable } from '@angular/core';
import { LoggerService } from ./logger.service';
import { UserService } from './user.service';
@Injectable() //1.添加装饰器`@Injectable()`
export class ContactService {
    //2.构造函数中注入所依赖的服务
    constructor(_logger:LoggerService,_userService:UserService){}
    getCollections() {
        this._logger.log('Getting contacts...');
    }
}

接下来,需要在组件中注册这个服务,这个服务可能会被多个模块调用,可以在根模块的providers元数据中注册它。

//...
//3.在组件的providers元数据中注册服务
providers:[ContactService,LoggerService,UserService]
//...

@Injectable不是必须的,只有当一个服务依赖其他服务的时候,才需要用@Injectable来显式装饰。推荐任何时候都加上@Injectable装饰器。

在模块中注入服务

在模块中注入的服务,属于这个模块的所有组件都能共享这个服务。
angular在启动程序时会启动一个根模块,并加载它所依赖的其他模块,此时会生成一个全局的根注入器,由该注入器创建的依赖注入对象在整个应用程序级别可见,并共享一个实例。同时,根模块会指定一个根组件并启动,由该根组件添加的依赖注入对象是组件树级别可见,在根组件以及子组件中共享一个实例。

//app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { LoggerService } from './shared/logger.service';
import { UserService } from './shared/user.service';
//假设有个单独的通讯录模块
import { ContactModule } from './contact.module';
@NgModule({
    imports:[
        BrowserModule,
        ContactModule
    ],
    declarations:[AppComponent],
    providers:[LoggerService,UserService],
    bootstrap:[AppComponent]
})
export class AppModule {}

Provider

Provider实现逻辑操作或数据操作的封装,以接口的方式提供给调用方使用。
在angular中,Provider描述了注入器如何初始化标识所对应的依赖服务,它最终用于注入到组件或者其他服务中。Provider提供了一个运行时所需的依赖,注入器依靠它来创建服务对象的实例。

@Component({
    providers:[{provide:LoggerService,useClass:LoggerService}]
})

上面代码的完整形式采用了对象字面量的方式来描述一个Provider的构成要素。其中provide属性可以理解为这个Provider的唯一标识,用于定位依赖值以及注册Provider,也就是应用中使用的服务名,而useClass属性则代表使用哪个服务类去创建实例。

Provider注册方式

Provider的主要作用是注册并返回合适的服务对象,angular提供了常见的四种Provider注册形式:

  • 类Provider
  • 值Provider
  • 别名Provider
  • 工厂Provider
类Provider

类Provider基于标识来指定依赖项,这种方式可以使得依赖项能够被动态指定为其他不同的具体实现,只要接口不变,对于使用方就是透明的。

//渲染方式
var injector=Injector.resolveAndCreate([
    {provider:Render,useClass:DomRender} //DOM渲染方式
    //{provider:Render,useClass:CanvasRender} //Canvas渲染方式
    //{provider:Render,useClass:ServerRender} //服务端渲染方式
]);
//调用方
class ApplicationComponent{
    constructor(_render:Render){
        _render.render();//渲染
    }
}
值Provider

依赖的对象不一定是类,也可以是常量、字符串、对象等其他数据类型的,这可以方便用在全局变量、系统相关参数配置等场景中。在创建Provider对象时,只需使用useValue就可声明一个值Provider。

let globalSetting={
    env:'production',
    getHost:()=>{ return 'https://angular.io' }
};
@Component({
    selector:'some-component',
    template:'<div>Some Component</div>',
    providers:[
        {provide:'urlSetting',useValue:globalSetting},//对象
        {provide:'NAME',useValue:'angular2'}//常量
    ]
})
export class SomeComponent{
    constructor() {}
}
别名Provider

有了别名Provider,就可以在一个Provider中配置多个标识,其对应的对象指向同一个实例,从而实现多个依赖、一个对象实例的作用。useExisting可以用来指定一个别名Provider。

//...
providers:[
    {provide:NewLoggerService,useClass:NewLoggerService},
    {provide:OldLoggerService,useExisting:NewLoggerService}
]
工厂Provider

有时候依赖对象是不明确且动态变化的,可能需要根据运行环境、执行权限来生成,Provider需要一种动态生成依赖对象的能力。angular提供的工厂Provider可以解决这个问题,它通过暴露一个工厂方法,返回最终依赖的对象。

let contactServiceFactory=(_logger:LoggerService,_userService:UserService)=>
    {
        return new contactService(_logger,_userService.user.isAuthorized);
    }
export let contactServiceProvider={
    { provide:ContactService,useFactory:contactServiceFactory,deps:[
        LoggerService,UserService
    ]}
}

使用工厂Provider的注册方式需要用useFactory来声明Provider是一个工厂方法deps是一个数组属性,指定了所需要的依赖,可以注入到工厂方法中。

相关文章

  • 开源项目的依赖注入

    开源项目的依赖注入 依赖注入概念 依赖注入(DI:Dependency Injection): 依赖注入方式: B...

  • 资料收集

    依赖注入 AngularJs依赖注入的研究 (已读) 依赖注入(已读)

  • Dagger2常用注解诠释

    依赖注入 控制反转(IoC)与依赖注入(DI)浅谈依赖注入理解依赖注入(IOC)和学习Unity Gradle配置...

  • Day62 Spring 依赖注入源码解析

    手动注入自动注入 依赖注入,set注入,构造注入 依赖注入: Key依据 byType byName constr...

  • Dagger2 源码分析

    Dagger简单介绍 Dagger2涉及到依赖注入,有关依赖注入的请到理解依赖注入 通过注解方式实现依赖注入分为两...

  • 依赖注入(转)

    依赖注入(转) 原文地址:依赖注入原理

  • Spring学习之依赖注入

    Spring学习之依赖注入 依赖注入的基本概念 依赖注入(Dependecy Injection),也称为IoC(...

  • 依赖注入及Dagger2框架简介

    依赖注入简介 在介绍Dagger框架之前我们先来看看依赖注入(Dependence Injection),依赖注入...

  • 浅谈依赖注入

    依赖注入是什么? 依赖注入的作用是什么? 依赖注入的应用场景? 如何实现依赖注入? 对于一个后端程序员来说,依赖注...

  • 依赖注入的方式

    依赖注入: 依赖于某些方式给Bean的资源进行注入 Spring 支持三种依赖注入的方式 属性注入 构造器注入 工...

网友评论

      本文标题:依赖注入

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