Angular2 小贴士-多级注入器

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: angular2 的依赖注入包含了太多的内容,其中的一个重点就是注入器,而注入器又非常难理解,今天我们不深入介绍注入器的内容,可以参考官方文档,我们今天来说注入器的层级。 也就是组件获取服务的容器会选择具体哪一个。

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

import {Component, Host}from '@angular/core';
import {LoggerService}from './logger.service';

@Component({
    selector: 'my-detailList',
    templateUrl: './app-detailList.component.html',
    moduleId: module.id,
    providers: [
        { provide: LoggerService, useClass: LoggerService }
    ]
})

export class AppDetailListComponent {
    constructor(   private logger: LoggerService) {

    }
    show(): void {
        this.logger.Debug();
    }

}

 

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,一个值得学习的东西。

 

我又回来了,回到了技术最前线,
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
JavaScript 测试技术
什么是 Angular 的多级注入器
什么是 Angular 的多级注入器
135 0
什么是 Angular 的多级注入器
|
JavaScript 程序员
Angular 通过依赖注入机制注入一个对象的例子,什么是 ElementInjector
Angular 通过依赖注入机制注入一个对象的例子,什么是 ElementInjector
135 0
Angular 通过依赖注入机制注入一个对象的例子,什么是 ElementInjector
Angular依赖注入的一个例子和注入原理单步调试
Angular依赖注入的一个例子和注入原理单步调试
105 0
Angular依赖注入的一个例子和注入原理单步调试
|
JavaScript 前端开发
Angular的HttpClient注入
Angular的HttpClient注入
106 0
Angular的HttpClient注入
Angular 依赖注入机制根据providers定义生成注入实例的框架代码
Angular 依赖注入机制根据providers定义生成注入实例的框架代码
108 0
Angular 依赖注入机制根据providers定义生成注入实例的框架代码
|
2月前
|
缓存 JavaScript 前端开发
Angular 应用打包和部署
Angular 应用打包和部署
167 58
|
9天前
|
缓存 监控 JavaScript
Angular 应用打包和部署
【10月更文挑战第16天】Angular 应用的打包和部署是一个综合性的过程,需要考虑多个方面的因素。通过合理的打包和部署策略,可以确保应用在生产环境中稳定运行,并为用户提供良好的体验。你需要根据实际情况选择合适的部署方式,并不断优化和改进部署流程,以适应业务的发展和变化。
|
3月前
|
应用服务中间件 Java Maven
掌控视图的力量!深入解析 JSF 视图管理,揭秘视图生命周期的秘密,让你的应用更高效!
【8月更文挑战第31天】JavaServer Faces (JSF) 是一种强大的框架,用于管理 Web 应用程序的视图。本文通过具体案例介绍 JSF 视图管理的基础知识,包括创建、管理和销毁视图的过程。首先,在 Eclipse 中创建一个新 JSF 项目,并配置 Maven 依赖。接着,在 `WEB-INF` 目录下配置 `web.xml` 文件,设置 JSF servlet。
49 0
|
3月前
|
Java Spring
🔥JSF 与 Spring 强强联手:打造高效、灵活的 Web 应用新标杆!💪 你还不知道吗?
【8月更文挑战第31天】JavaServer Faces(JSF)与 Spring 框架是常用的 Java Web 技术。本文介绍如何整合两者,发挥各自优势,构建高效灵活的 Web 应用。首先通过 `web.xml` 和 `ContextLoaderListener` 配置 Spring 上下文,在 `applicationContext.xml` 定义 Bean。接着使用 `@Autowired` 将 Spring 管理的 Bean 注入到 JSF 管理的 Bean 中。
57 0
|
3月前
|
开发者 Java 开发框架
JSF与EJB,打造企业级应用的神器!让你的Web应用更加稳定、高效!
【8月更文挑战第31天】在现代企业级应用开发中,JSF(JavaServer Faces)与EJB(Enterprise JavaBeans)是两大核心技术。JSF作为一款基于Java的Web应用框架,以其丰富的UI组件和表单处理功能著称;EJB则专注于提供分布式事务处理及远程调用等企业级服务。两者的结合为企业应用带来了高效便捷的开发模式。下文将通过一个简单的示例展示如何利用JSF进行用户信息的输入与保存,并借助EJB实现相关业务逻辑。尽管这一组合具有明显优势,但在实际应用中还需考虑其局限性并作出合理选择。
51 0