在angular2服务中注入服务

http://kittencup.com/javascript/2015/11/11/%E5%9C%A8angular2%E6%9C%8D%E5%8A%A1%E4%B8%AD%E6%B3%A8%E5%85%A5%E6%9C%8D%E5%8A%A1.html

如果你关注我们的文章 Angular2中的依赖注入,你知道DI系统在Angular中是如果运作的,它利用在我们代码上通过注解添加metadata来获取所有关于依赖的信息来解决我们的依赖关系

Angular 2 应用基本上可以用任何语言编写。只要它以某种方式编译成JavaScript,当我们使用Typescript编写我们应用时,我们使用decorator来给我们代码添加metadata,有时,我们甚至忽略一些decorator,单纯依靠类型注释。然而,事实证明,当涉及到DI,我们可能注入依赖到服务时遇到意外的行为。

本文讨论了这个意外的问题,为什么它存在,以及如何解决。

注入服务依赖

比方说我们有一个简单的Angular 2 组件有一个DataService依赖,它可能是这个样子:

@Component({
  selector: ‘my-app‘
})
@View({
  directives: [NgFor],
  template: `
    <ul>
      <li *ng-for="#item in items"></li>
    </ul>
  `
})
class AppComponent {
  items:Array<any>;
  constructor(dataService: DataService) {
    this.items = dataService.getItems();
  }
}

另一方面 DataService 是一个简单的类(因为它在Angualr2是一个服务),它提供了一个方法返回一些items

class DataService {
  items:Array<any>;

  constructor() {
    this.items = [
      { name: ‘Christoph Burgdorf‘ },
      { name: ‘Pascal Precht‘ },
      { name: ‘thoughtram‘ }
    ];
  }

  getItems() {
    return this.items;
  }
}

当然,为了能使用DataService类型,我们必须为injector添加这个provider,当引导我们的应用时可以这样做,通过传递一个provider给boostrap();

bootstrap(AppComponent, [DataService]);

到现在为止没有什么新的内容,如果这对你来说是新内容,你可能需要先阅读我们的Angular2中的依赖注入文章。

那么问题在那里呢? 这个问题发生在当我们试图注入一个依赖进我们的服务,比如,我们可以使用Http在我们的DataService里从远程服务器获取数据,让我们快速实现这个。首先,我们需要为injector提供一个provider,让DataService知道有关http。

import {HTTP_PROVIDERS} from ‘angular2/http‘;

...

bootstrap(AppComponent, [HTTP_PROVIDERS, DataService]);

Angular http模块 暴露了 HTTP_PROVIDERS,它包含了所有的我们需要用到的http操作的provider,接下来,我们需要在我们的服务中注入这个实例

import {Http} from ‘angular2/http‘;

class DataService {
  items:Array<any>;

  constructor(http:Http) {
    ...
  }
  ...
}

轰. 这个东西会爆炸。当我们在浏览器中运行这段代码,我们会得到以下错误:

Cannot resolve all parameters for DataService(?). Make sure they all have valid type or annotations.

这错误基本上的意思是,它不能解决DataService的Http依赖,因为Anuglar不知道该类型,因此 没有provider可以用来解决该依赖,恩。。等等,我们没有将变量类型提供给了constructor吗?

不,我们提供了,不幸的是,这是不够的,但是 在我们的AppComponent我们注入的DataService显然是在正常工作,那在这里有什么问题?

在我们的Annotation和Decorator之间的区别文章,我们获悉,decorator只是简单的为我们的代码添加metadata,我们来看下编译后的AppComponent的decorator

function AppComponent(myService) {
  ...
}

AppComponent = __decorate([
  Component({...}),
  View({...}),
  __metadata(‘design:paramtypes‘, [DataService])
], AppComponent);

我们可以清楚地看到,AppComponent类会被__decorate函数给包装,里面包装了Component,View 和 paramtypes的metadata,

paramtypes 元素是一个告诉angular DI用来弄清楚,它必须返回一个什么类型的实例

这看起来很不错。让我们来看看被编译后的DataService,看看在那里发生了什么事情(也简化了)。

DataService = (function () {
  function DataService(http) {
    ...
  }
  return DataService;
})();

哎呀。显然,在这里没有任何metadata。这是为什么?

当设置了emitDecoratorMetadata选项,TypeScript会生成metadata,然而,这并不意味着它会盲目的为我们代码的每个类或方法生成metadata,TypeScript只会对那些被decorator附加的类,方法,属性或者构造函数参数来生成相应的metadata ,否则,会产生大量的未使用的metadata代码,这不仅影响文件的大小,也对我们的应用程序运行产生影响。

这就是为什么AppComponent会生成metadata,而DataService 不生成,我们的AppComponent有一个decorator

强制生成metadata

那么我们如果才能强制TypeScript为我们生成metadata呢,我们可以做的一件事,就是用框架提供的Di decorator,正如我们在DI的其他文章中了解到,@Inject decorator用来要求某种类型的依赖

我们可以改变我们的DataService的成这样的:

import {Inject} from ‘angular2/core‘;
import {Http} from ‘angular2/http‘;

class DataService {
  items:Array<any>;

  constructor(@Inject(Http) http:Http) {
    ...
  }
  ...
}

问题解决。事实上,如果查看经过编译后的代码时会发现已生成需要的metadata

function DataService(http) {
}
DataService = __decorate([
  __param(0, angular2_1.Inject(Http)),
  __metadata(‘design:paramtypes‘, [Http])
], DataService);

我们基本上可以在我们代码上做任何decorator,只要在class,或者构造函数参数上附加任何decorator,换一种说法,我们可以把 @Inject 移除,然后在这个类上使用别的decorator,因为这将导致TypeScript为构造函数参数生成metadata

当然。在一个类上使用一个decorator,来解决所有的问题,听起来不是很合适。幸运的是,我们可以使用Angular自带的另一个decorator。@Injectable 是一个用于Dart的metadata创建,在TypeScript,它没有任何特殊含义,然而,事实证明是非常适合我们的用例.

我们所要做的就是导入它,把它放在我们的DataService

import {Injectable} from ‘angular2/core‘;
import {Http} from ‘angular2/http‘;

@Injectable()
class DataService {
  items:Array<any>;

  constructor(http:Http) {
    ...
  }
  ...
}

同样,它只是强制TypeScript发射需要的matadata,这个decorator在这里并没有什么特殊含义,这似乎是我们目前解决所示问题的最佳选择

时间: 2024-10-11 22:06:43

在angular2服务中注入服务的相关文章

Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)

导读 我们知道在基于Spring Cloud的微服务体系中,各个微服务除了在内部提供服务外,有些服务接口还需要直接提供给客户端,如Andirod.IOS.H5等等. 而一个很尴尬的境地是,如果直接将提供外部接口的微服务暴露给公网,那么意味着为了增强这个微服务的安全性,需要做很多额外的安全性措施,如报文数字签名.加密等:而大部分场景下,微服务本身又是提供给内部其他微服务调用的,即便所有的微服务都会不同程度地直接面向App客户端提供公网服务,那么为了这确保这些微服务的安全性,涉及的微服务也都需要实现

避免在ASP.NET Core 3.0中为启动类注入服务

本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇. Part 1 - 将.NET Standard 2.0类库转换为.NET Core 3.0类库 Part 2 - IHostingEnvironment VS IHostEnvironent - .NET Core 3.0中的废弃类型 Part 3 - 避免在ASP.NET Core 3.0中为启动类注入服务(本篇) Part 4 - 将终端中间件转换为ASP.NET Core 3.0中的端点路由 Part 5 - 将集成测试的

REST服务中的异常处理

在REST服务中,服务端如果产生了异常信息,无论是业务异常或是系统异常,如果直接将异常抛出,在客户端浏览器中,是无法获取异常的详细,只能获取一个StateCode 500 Internal Server Error错误,如下: HTTP/1.1 500 Internal Server Error Content-Length: 56 Content-Type: text/xml; charset=utf-8 Server: Microsoft-HTTPAPI/2.0 Date: Tue, 14

wildfly 实践5 ---分布式服务中的JMS服务访问

实践条件与目标: 1. 分布式服务中主从服务相关配置 2. 从服务中主要代码片段展示 3. 此次使用wildfly10,因为其默认的jms服务是activemq. 步骤: 主服务配置中使用standalone-full.xml启动,其自带activemq模块. 使用adduser增加应用程序用户名称为guest,密码为guest,角色为guest,增加应用程序用户ejbuser,密码123. 配置文件中找到activemq模块,并修改配置如下: <subsystem xmlns="urn:

IT运维服务中的一些工作思路探索(一)

再引用一句老话:纲举目张!,IT运维工作要有成效,需让我们又见树木又见森林,于是我把有关运维工作开展思路.方法及原则进行归纳整理,与大家一起探讨. 一. 运维工作目标 运维工作的核心目标是保持并提高用户满意度,从服务中挖掘服务,各项运维工作就应该紧密围绕该目标开展.在此基础上,才能促进公司不断的发展壮大.因此,始终将提升客户满意度作为运维服务的宗旨才能不断推动公司不断发展,让运维始于"扎根",终于"参天大树".这样的发展是有根基的,是持久的.有潜力的. 在此过程中,

ignite服务中的bean注入为空

在写ignite服务的时候,通常服务配置在启动文件中: <bean class="org.apache.ignite.services.ServiceConfiguration"> <property name="name" value="***Impl" /> <property name="maxPerNodeCount" value="1" /> <prope

PHP中的服务容器与依赖注入的思想

依赖注入 当A类需要依赖于B类,也就是说需要在A类中实例化B类的对象来使用时候,如果B类中的功能发生改变,也会导致A类中使用B类的地方也要跟着修改,导致A类与B类高耦合.这个时候解决方式是,A类应该去依赖B类的接口,把具体的类的实例化交给外部. 就拿我们业务中常用的通知模块来说. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php /**  * 定义了一个消息类  * Class Messag

SSH项目中遇到拦截器无法注入服务的问题

配置applicationContext.xml,给自定义拦截器增加了properity属性是一个biz,运行的时候一直报空指针异常,输出结果biz总是null,很是好奇,难不成拦截器无法被注入么? - -后来试了一下biz直接实例化,结果还是...空指针...实在想不明白...没法子..最后把数据提前取出来,存在session当中,在拦截器中先从session中取出来数据,然后....在做判断拦截了~~ 有人知道如何在拦截器中注入biz或者dao么?

Angular2入门系列教程-服务

上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得我们可以很优雅得做到这一点.这里简单描述下,依赖注入可以使我们在编写代码的时候不用使用new 去生成一个类,这样就达到了解耦的目的,更多关于依赖注入的知识我觉得不应该在这里讲解 和其他方式类似,Angular2使用的是装饰器@Injectable()来描述以一个类是否可注入,我们本篇文章的目的,就是