angular2 的依赖注入包含了太多的内容,其中的一个重点就是注入器,而注入器又非常难理解,今天我们不深入介绍注入器的内容,可以参考官方文档,我们今天来说注入器的层级。

也就是组件获取服务的容器会选择具体哪一个。

先简单介绍一个背景:有3个组件AppComponent 根组件、DetailList组件 ( 日志列表组件)、Detail组件( 日志组件)。

这三个组件会形成一个组件树,对应的我们也可以认为每个组件都会有一个独立的注入器(有时候不会出现,但是可以这么认为)。

加入一个日志服务LoggerService,如果按照我们普通的入门方式,在根模块providers 中提供LoggerService。那么在整个应用程序中,LoggerService只有一个实例,什么意思呢?就是说无论在哪个组件,获取到的都是首次创建的LoggerService,所有组件共用一个服务实例,这有时候会是一个有用的特性,比如我们使用的全局配置。

全局唯一不是我们这次要验证的重点,因为这个太普通,我们这次要说明的是我们如何在每个组件中都获取单独的LoggerService实例,即每个组件的实例都不同。这个就需要对ng2的依赖注入有所了解才可以。

我们逐步来说明如何实现?

为了便于看到这篇短文的同学有所了解,我加入一些基础代码。

1.app.module.ts 应用程序根模块。注意此处我们没有在Providers中注册loggerService。当然注册了通过后面的方法也可以达到我们的目的。

  1. import { NgModule, Optional, SkipSelf, ReflectiveInjector} from '@angular/core';
  2. import { BrowserModule } from '@angular/platform-browser';
  3.  
  4. /* App Root */
  5. import { AppComponent } from './app.component';
  6. import { routing } from './app.routing';
  7. import { Title } from '@angular/platform-browser';
  8. import {MessagesModule, GrowlModule, ButtonModule}from 'primeng/primeng';
  9. import {AppDetailComponent}from './app-detail.component';
  10. import {AppDetailListComponent}from './app-detailList.component';
  11. import {LoggerService}from './logger.service';
  12. let allTitle:string="郭志奇";
  13.  
  14. @NgModule({
  15. imports: [
  16. BrowserModule,
  17. MessagesModule,
  18. GrowlModule, ButtonModule
  19. ],
  20. declarations: [AppComponent, AppDetailComponent, AppDetailListComponent],//声明当前模块需要的指定 组件信息
  21. exports: [],
  22. providers: [Title],
  23. bootstrap: [AppComponent]
  24. })
  25. export class AppModule {
  26. constructor( @Optional() @SkipSelf() parentModule: AppModule) {
  27. console.log(parentModule);
  28. if (parentModule) {
  29. throw new Error(
  30. 'AppModule is already loaded. Import it in the AppModule only');
  31. }
  32. }
  33. }

2.app.component.ts  应用程序根组件

  1. import { Component, ViewEncapsulation, Host, ViewContainerRef, ReflectiveInjector } from '@angular/core';
  2. import { Title } from '@angular/platform-browser';
  3. import { Message } from 'primeng/primeng';
  4. import {LoggerService}from './logger.service';
  5. @Component({
  6. selector: 'my-app',
  7. moduleId: module.id,
  8. templateUrl: './app.component.html',
  9. providers: [
  10. { provide: LoggerService, useClass: LoggerService }
  11. ]
  12. })
  13. export class AppComponent {
  14. subtitle = '(Final)';
  15. private msgs: Message[];
  16. constructor(private title: Title, @Host() private logger: LoggerService) {
  17. this.title.setTitle("AppComponent");
  18. }
  19.  
  20. show(): void {
  21. this.logger.Debug();
  22. }
  23. }

请注意,我们在跟组件中providers中注册了LoggerService。

3.app.detailList.ts  日志列表中providers中也注册了LoggerService

  1. import {Component, Host}from '@angular/core';
  2. import {LoggerService}from './logger.service';
  3.  
  4. @Component({
  5. selector: 'my-detailList',
  6. templateUrl: './app-detailList.component.html',
  7. moduleId: module.id,
  8. providers: [
  9. { provide: LoggerService, useClass: LoggerService }
  10. ]
  11. })
  12.  
  13. export class AppDetailListComponent {
  14. constructor( private logger: LoggerService) {
  15.  
  16. }
  17. show(): void {
  18. this.logger.Debug();
  19. }
  20.  
  21. }

4.app.detail.ts  日志组件providers没有注册LoggerService。

  1. import {Component, Host}from '@angular/core';
  2. import {LoggerService}from './logger.service';
  3. @Component({
  4. selector: 'detail',
  5. moduleId: module.id,
  6. templateUrl: './app-detail.component.html',
  7. providers: [
  8. // { provide: LoggerService, useClass: LoggerService }
  9. ]
  10. })
  11.  
  12. export class AppDetailComponent {
  13. constructor( private logger: LoggerService) {
  14.  
  15. }
  16. show(): void {
  17. this.logger.Debug();
  18. }
  19.  
  20. }

现在我们通过chrome来看一下 LoggerService的层级关系。

通过查看依赖关系图,我们可以看到AppComponent组件使用了单独的LoggerService,DetailList组件也使用单独的LoggerService 实例,而Detail组件使用的是父组件DetailList的LoggerService实例。

目前来看没有达到我们的要求,我们的要求是每个组件都有单独的LoggerService实例,那么我们假设Detail组件的providers是我们忘记输入的,很难测试出原因所在。那么我们加入一个@Host()来限制注入器的查找范围。

对于注入器的向上查找方式,请参考官方文档。

为了便于调试,我们加入@Host().

@Host 装饰器将把往上搜索的行为截止在 宿主组件

detail.ts 提示detail组件加入@Host()装饰器

  1. import {Component, Host}from '@angular/core';
  2. import {LoggerService}from './logger.service';
  3. @Component({
  4. selector: 'detail',
  5. moduleId: module.id,
  6. templateUrl: './app-detail.component.html',
  7. providers: [
  8. // { provide: LoggerService, useClass: LoggerService }
  9. ]
  10. })
  11.  
  12. export class AppDetailComponent {
  13. constructor( @Host() private logger: LoggerService) {
  14.  
  15. }
  16. show(): void {
  17. this.logger.Debug();
  18. }
  19.  
  20. }

会提示找不到LoggerService的实例,@Host()的作用就是限制注入器查找到当前组件就停止,不会继续往上查找。所以会出现找不到Providers的错误。

加上providers 的结果就是我们想要的了。

完美的解决了多组件使用单独服务实例的问题。

总结:

1.如果要使组件单独使用服务,那么首先要在providers 中单独注册该服务。很容易理解

2.为了更好的检测可能出现的问题,在组件服务上加入@Host()装饰器,可以尽量早的抛出错误信息

3.使用ng2的debug工具

4.要明确各组件之间的关系,因为不同的组件关系会导致服务的实例的不同

5.服务尽量是模块级,不是应用级。

angular2,一个值得学习的东西。

Angular2 小贴士-多级注入器的更多相关文章

  1. Angular2 小贴士 Name

    Angular2 正式版已经发布了一个月了,我也是通过各种方式在进行验证是否可以满足我们的需求,今天我就发现了一个问题.现在我们来一起说明一下,这个可能不算是bug,而应该需要我们记住就可以了. 我们 ...

  2. Angular2 小贴士 RouterLink 导航

    AngularJS的路由一直是学习的一大难点,我们只能边看边学边掌握,边看边学边推翻.今天我们来看一下在angular2中通过routerLink实现导航的几种方式,以及各自的优缺点. Angular ...

  3. Angular2 小贴士 NgModule 模块

    angular2 具有了模块的概念,响应了后台程序的号召,高内聚 低耦合.模块就是用来进行封装,进行高内聚  低耦合的功能. 其实各人认为ng2 的模块和.net的工程类似,如果要使用模块中定义的功能 ...

  4. 【小贴士】虚拟键盘与fixed带给移动端的痛!

    前言 今天来公司的主要目的就是研究虚拟键盘与fixed的问题,期间因为同事问起闭包与事件委托(阻止冒泡)相关问题,便穿插了一篇别的: [小贴士]工作中的”闭包“与事件委托的”阻止冒泡“,有兴趣的朋友可 ...

  5. SVN小贴士

    我辛辛苦苦写的到哪里了? SVN小贴士SVN服务器上的代码项目组公用,你的每一个提交都会体现给项目组每个人,所以提交要慎重,要注意避免代码冲突,使用SVN小贴士: 1.提前宣布开发计划,保持项目组成员 ...

  6. android性能小贴士 翻译

    转自http://developer.android.com/training/articles/perf-tips.html 性能小贴士: 这篇文档主要一些微优化可以提升应用程序性能,但是这些改变不 ...

  7. 小贴士——提高PHP程序在NGINX代理服务器的性能

    NGINX本身就是面向最大性能的代理服务器,因此在使用NGINX,并没有性能调整的配置工作.但是却有很多选项可用于定制NGINX的行为,利用底层硬件和操作系统. 下面将介绍用于提供PHP在NGINX的 ...

  8. jprofiler8使用小贴士

    说明:本文的小贴士是针对jprofiler8的,其他版本上可能有不适用的地方 贴士一:使用jpenable监控,无需增加jvm参数和重启 贴士一:使用jpenable监控,无需增加jvm参数和重启 j ...

  9. 初识bd时的一些技能小贴士

    既然小豆腐如此给力,而且充分的利用主动学习的优势,已经有了迅速脑补,压倒式的优势,不过这只是表面而已,一切才刚刚开始,究竟鹿死谁手,还有待验证. 以上可以看到,小豆腐为什么拼命的要teach我们了么, ...

随机推荐

  1. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  2. 如果你也会C#,那不妨了解下F#(7):面向对象编程之继承、接口和泛型

    前言 面向对象三大基本特性:封装.继承.多态.上一篇中介绍了类的定义,下面就了解下F#中继承和多态的使用吧.

  3. UML图中经常用到几种的关系图例

    学习这个东西挺奇怪的,时间一长就容易忘记,或者记不清楚.今天看到一些UML图的关系,发现有些出入了,索性就写下来,以后再忘记的时候过来看看. 在UML的类图中,常见的有以下几种关系: 继承(Gener ...

  4. HttpPost过程中使用的URLEncoder.encode(something, encode)

    URLEncoder.encode("刘美美", "utf-8").toString()       =     %E5%88%98%E7%BE%8E%E7%B ...

  5. Win7安装MySQL-5.7.16过程

    1.在C盘新建MYSQL文件夹:2.将mysql-5.7.16-winx64拷贝到C:\MYSQL文件夹下,更名为mysql-5.7.16:3.在mysql-5.7.16目录下,建my.ini文件,内 ...

  6. 《Note --- Unreal --- MemPro (CONTINUE... ...)》

    Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...

  7. angularJS(5)

    angularJS(5) 一,数据循环:特别要注意作用域 使用ng-repeat指令. <div ng-app="myApp" ng-controller="myC ...

  8. 二次剩余、三次剩余、k次剩余

    今天研究了一下这块内容...首先是板子 #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  9. 学习笔记:URL Protocol在浏览器中打开本地应用程序

    看到阿里的网站上可以通过点击卖家的旺旺图标从而调用本地的阿里旺旺程序,而且还可以传递当前浏览者需要咨询的商品.这是怎么实现的呢?是通过URLProtocol来完成. 原理还没有太清楚,即在系统里注册一 ...

  10. 写给.NET开发者的数据库Migration方案

    微软给我们提供了一种非常好用的数据库迁移方案,但是我发现周围的同学用的并不多,所以我还是想把这个方案整理一下..NET选手看过来,特别是还在通过手工执行脚本来迁移数据库的同学们,当然你也可以选择EF的 ...