美文网首页
Angluar4的注入器与提供器

Angluar4的注入器与提供器

作者: 南蓝NL | 来源:发表于2017-11-17 22:20 被阅读0次
    constructor(private ProductService:productService){...}//注入器
    //提供器
    providers:[productService]
    providers:[{provide:productService,useClass:productService}]
    providers:[{provide:productService,useClass:AnotherProductService}]
    providers:[{provide:productService,useFactory:() =>{...}}]
    

    首先我们来看一个简单的例子

    一个简单依赖注入样例.png
    ng g service shared/product  //创建一个服务
    

    在创建好的项目里的shared文件里的product.service.ts写入

    import { Injectable } from '@angular/core';
    @Injectable() //这个装饰器的作用是决定着ProductService可以通过构造函数注入其它的服务,
                 // 现在是ProductService能否注入到其它的服务中去,是由模块的提供器决定的
                 //如app.modules.ts的 providers: [ProductService],
    export class ProductService {
    //这里是想实现服务注入到服务
      constructor() {}
       getProduct():Product{
         return new Product(0,"iphone7",5899,"最新款苹果手机")
       }
      }
      export class Product {
        constructor(
            public id:number,
            public title:string,
            public price:number,
            public desc:string
        ){}
      }
    

    然后在product1.component.ts通过构造函数创建注入器

    import { Component, OnInit } from '@angular/core';
    import {Product} from "../shared/product.service";
    import {ProductService} from "../shared/product.service";
    @Component({
      selector: 'app-product1',
      templateUrl: './product1.component.html',
      styleUrls: ['./product1.component.css']
    })
    export class Product1Component implements OnInit {
       product: Product;
       constructor(private productService:ProductService) { }
      ngOnInit() {
        this.product = this.productService.getProduct();
      }
    }
    

    在然后在app.component.ts里面创建提供器

      providers: [ProductService]
    

    接下来在product1.componet.html里面绑好数据

    <div>
      <h1>商品详情</h1>
      <h2>名称:{{product.title}}</h2>
      <h2>价格:{{product.price}}</h2>
      <h2>描述:{{product.desc}}</h2>
    </div>
    

    最后在app.component.html里面注册product1组件

        <app-product1></app-product1>
    

    提供器的作用域

    上文我们是把提供器放在app.component.ts中,这次我们把提供器放在自身的组件当中,唯一的区别是把提供器放在product2.component.ts中

    @Component({
      selector: 'app-product2',
      templateUrl: './product2.component.html',
      styleUrls: ['./product2.component.css'],
      providers:[{
        provide:ProductService(指定了一个token),useClass:AnotherProductService (实   例化一个对象)
      }]
    })
    export class Product2Component implements OnInit {
      product: Product;
      constructor(private productService:ProductService) { }
      ngOnInit() {
        this.product = this.productService.getProduct();
      }
    }
    
    

    关于提供器的作用域的几个注意点

    1. 提供器如果声明在app.component.ts模块中,那么它的作用域对于所有组件来说都是可见的
    2. 提供器如果声明在组件当中,那么只有它本身的组件及子组件是可见的
    3. 如果定义了相同的token,组件的token会覆盖模块的token
    4. 优先将提供器声明在模块中

    服务之间的注入

    新建服务命令

    ng g service shared/logger
    

    logger.service.ts

    @Injectable()
    export class LoggerService {
      constructor() { }
       log(message:string){
         console.log(message);
       }
    }
    

    product.service.ts

    import { Injectable } from '@angular/core';
    import {LoggerService} from "./logger.service"
    @Injectable() /
    export class ProductService {
    //这里是想实现服务注入到服务
      constructor(public logger:LoggerService) {}
       getProduct(): Product{
         this.logger.log("getProduct方法被调用");
         return new Product(0,"iphone7",5899,"最新款苹果手机")
       }
      }
      export class Product {
        constructor(
            public id:number,
            public title:string,
            public price:number,
            public desc:string
        ){}
      }
    

    在another.service.ts中这里会报一个错误,引起的原因是在构造函数的声明没有和父类保持一致


    another.service.ts报错.png

    解决办法是:因为another使用的是product服务,product.service.ts的构造函数声明了logger服务,another作为子类与父类保持一致,所以也要在构造函数里面进行声明

    @Injectable()
    export class AnotherProductService implements  ProductService{
      getProduct():Product {
        return new Product(1,"iphoneX",8888,"买不起买不起")
      }
      constructor(public logger:LoggerService) {
          }
    }
    
    

    使用工厂模式声明提供器

     providers: [{
        provide:ProductService,
        useFactory:() =>{
          let logger = new LoggerService();
          let dev = Math.random()>0.5;
          if(dev){
            return new ProductService(logger);
          }else{
            return new AnotherProductService(logger);
          }
        }
      },LoggerService],
      bootstrap: [AppComponent]
    })
    

    一般来说可以传值

      providers: [{
        provide:ProductService,
        useFactory:(logger:LoggerService,isDev) =>{
          if(isDev){
            return new ProductService(logger);
          }else{
            return new AnotherProductService(logger);
          }
        },
        deps:[LoggerService,"IS_DEV_ENV"]
      },LoggerService,{
         provide:"IS_DEV_ENV",useValue:false
      }],
      bootstrap: [AppComponent]
    })
    

    也可以传一个对象

      providers: [{
        provide:ProductService,
        useFactory:(logger:LoggerService,appConfig) => {
          if(appConfig.isDev){
            return new ProductService(logger);
          }else{
            return new AnotherProductService(logger);
          }
        },
        deps:[LoggerService,"APP_CONFIG"]
      },LoggerService,{
         provide:"APP_CONFIG",useValue:{isDev:false}
      }]
    

    等下,究竟发生了什么事。让我们看看product2.component.ts中的主要代码

    export class Product2Component implements OnInit {
      product: Product;
      constructor(private productService:ProductService) { }
      ngOnInit() {
        this.product = this.productService.getProduct();
      }
    }
    

    梳理下整个过程。首先在商品组件里面的构造函数里声明了productService的token来注入服务,Ng看到之后会去找ProductService对象的提供器,然这个对象是使用工厂模式来实例化的,然后又发现这个工厂需要依赖于另外一个服务,根据这个服务的提供器声明去找,直到把所有的组件都组装好,而productComponent这个组件完全是透明的,服务和组件隔离开来,让组件更好地复用。


    image.png

    注入器及其层次关系

    注入器.及其层次关系.png

    子组件会根据自己的注入器查看本身有没有注册提供器,如果没有的话,就会根据注入器的token(这里的token是一个服务)查父组件app.component.ts的注入器上是否有合适的提供器,如果还是没有,则继续往上找,找到应用层注入器,看应用级的注入器有没有合适的提供器,即使app.modules.ts。如果还是没有,则会抛出异常。还有一点,值得注意的是,Angluar只能通过构造函数来注入,其他语言中不止局限于这一种。

    相关文章

      网友评论

          本文标题:Angluar4的注入器与提供器

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