繁体   English   中英

反射式注入器与角度注入器之间的区别

[英]Difference between Reflective Injector and Injector in Angular

我试图使用两种方法显式创建依赖关系。 两者几乎相同,但我有点混淆使用反射式喷射器比普通喷射器的优势,推荐哪种方式?

使用喷油器

import { Injector } from '@angular/core';
constructor( private injector: Injector) {
    this.myService = this.injector.get(MyService);
  }

使用反射式喷油器

import { ReflectiveInjector } from '@angular/core';
 constructor() {

       var injector= ReflectiveInjector.resolveAndCreate([MyService]);
       let myservice=injector.get(MyService);
     }

注射器是带有提供者/服务的容器。 它实现一种方法get并返回服务的实例。 让我们用JS伪代码实现注入器的最基本版本:

class ReflectiveInjector {
   providers = [];

   static resolveAndCreate(providers) {
     providers.forEach((provider)=>{
         providers.push({token: provider.provide, instance: new provider.useClass})
     });  
  )}

  get(dep) {
     return providers.find((provider)=>{ return provider.token === token });
  }
}

现在,我们需要先创建注入器的实例,然后才能使用它。 当我们创建它时,我们定义了提供者:

const existingInjector = ReflectiveInjector.resolveAndCreate([{provide: A, useClass: A }]);
const AInstance = existingInjector.get(A);

因此,您看到为了使用注射器,必须首先创建它。 它没有允许添加提供者的任何特定方法,因此在创建之后,我们无法向其添加任何新的提供者。

Angular 已经创建了您注入到组件构造函数中的注入器。 您不能向其添加任何内容,并且只能查询已经在其上定义的提供程序。 如果需要提供B级,则无法使用现有的进样器进行。 您需要一个新的。 这就是ReflectiveInjector类的来源。它允许您通过创建注射器的新实例并注册新的提供程序来添加新的提供程序。 好处是它还可以设置喷射器链。

让我们修改resolveAndCreateget允许链接注入器的方法:

class ReflectiveInjector {
   providers = [];
   parent;

   static resolveAndCreate(providers, parent) {
       this.parent = parent;
   ...
   }

   get(dep) {
       let found = providers.find((provider)=>{ return provider.token === token });
       if (!found && parent) {
            found = parent.get(dep);
       }

       return found;
   }

所以现在剩下的就是使用它:

// passing existingInjector as a parent
const childInjector = ReflectiveInjector.resolveAndCreate([{provide: B, useClass: B }], i);
const AInstance = childInjector.get(A);
const BInstance = childInjector.get(B);

现在,假设有人可能想要访问我们existingInjector 我们需要一个令牌来获取这个现有的注射器。 让我们这样定义令牌:

abstract class Injector {}

并编写一个可以获取现有注射器的函数:

function resolveDependency(token) {
   if (token === Injector) {
       return existingInjector;
   }
}

现在假设Angular在执行组件的构造函数,使用您指定的标记获取依赖项并将它们传递给resolveDependency函数时。 所以你这样写:

// the Injector here is a reference to our abstract Injector class and simply used as a token
MyComp {
   constructor(private injector: Injector) { ...  }
}

这里的令牌是Injector ,正如我所说的,它被传递到resolveDependency函数中,并返回现有的注射器。

Angular只会为每个提供程序创建一次实例。 因此,如果您想将Injector用作工厂,则不能。 您必须为所需对象的每个新实例创建一个新的注射器。

假设我们有一个名为ReportsService的服务类,它需要在运行时创建Record对象,但是您希望Record是可注入的。

这是我们需要创建其多个实例的类。

@Injectable() // does not have to be defined in ngModule
export class Record {
      // just an example dependency that ReportsService doesn't know about
      public constructor(http: Http) {
      }
}

这是将创建上述类的服务。

@Injectable() // exported via ngModule
export class RecordsService {
      // we need injector as parent otherwise Record class will not find Http
      public constructor(private parent: Injector) {
      }

      // factory method
      public createRecord(): Record {
          // creates a new injector that knows about Record but extends existing injector
          let injector = ReflectiveInjector.resolveAndCreate([
             {provide: Record, useClass: Record}
          ], this.parent);

          // first call, object is created
          let record = injector.get(Record);
          // just an example
          let example = injector.get(Record);
          // will output true
          console.log(record === example ? 'true' : 'false');

          return record;
     }
}

现在,一个新的Record实例很棒,但是如果每个对象都完全相同又有什么用呢? 因此,我们需要为Record注入参数。 我们将为字符串值创建令牌。

export const RECORD_URL = new InjectionToken<string>('record-url');

@Injectable()
export class Record {
      public constructor(http: Http, @Inject(RECORD_URL) url: string) {
      }
}

现在更新创建功能

 public createRecord(url: string): Record {
     let injector = ReflectiveInjector.resolveAndCreate([
        {provide: Record, useClass: Record},
        {provide: RECORD_URL, useValue: url
     ], this.parent);
     return injector.get(Record);
 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM