【问题标题】:Angular 2 Inject Dependency outside ConstructorAngular 2在构造函数之外注入依赖
【发布时间】:2016-12-30 07:45:19
【问题描述】:

我目前正在研究 Angular 2 中的 DI。我正在使用通用子类型实现 REST 客户端,具体数据类型如下:

class RESTClient<T>{
    constructor() {
        var inj =  ReflectiveInjector.resolveAndCreate([HTTP_PROVIDERS]);
        this.http = inj.get(Http);
        this.conf = RESTConfiguration;
    }
}
class BookClient extends RESTClient<Book>{      
    constructor(){
        // since I dont want to inject the HTTP Providers here, I'm using a custom    injector in the super class
        super();
    }
}

class WriterClient extends RESTClient<Writer>{      
    ...
    ...
}

据我了解,由超类 REST-Service 注入的所有 RESTClients 之间将共享一个 http 服务。

现在我想要一个这样的 RESTConfiguration 类:

@Injectable()
export class RESTConfiguration {
    get baseURL() {
     return this._baseURL;
    }

    set baseURL(value) {
        alert("sets value to"+value);
        this._baseURL = value;
    }

    private _baseURL;

}

应该在主应用中这样配置:

initializeApp(){
  this.restconf.baseURL = "http://localhost:3004/";
}
bootstrap(MyApp, [RESTConfiguration]).then();

我现在想知道如何将我的 RESTConfiguration 的一个单例实例注入 RESTService 类而不将其传递给我希望保持无参数的构造函数,以减少代码重复并避免打字稿中的泛型问题。

在上面的示例(第一个代码 sn-p)中,我尝试使用我创建的 ReflectiveInjector 注入我的配置,它为我提供了我的配置的自定义实例。

我想了几个解决方案:

  1. 通过使用服务或某些静态类属性使应用程序“全局注入器”可用来访问应用程序“全局注入器”

  2. 在我的配置中实现额外的单例逻辑

  3. 找到在构造函数之外使用 angular-native 注入方法的方法?

我的想法有错误还是我滥用了 DI 框架?

【问题讨论】:

  • 在阅读了上面的链接问题之后,我对作者很有感觉-我倾向于使用他的“肮脏的黑客”来让类通过全局注入器-我绝对不想重复代码在〜20-30班。有什么办法可以解决这个问题?如上所示,自定义注射器的方式如何?然后我可以直接将配置附加到我的服务或使其只是一个简单的静态类...
  • 这会创建一个独立的注入器。此自定义注入器不会返回在任何模块中注册的提供程序以及为这些提供程序创建的实例。您可以按照链接问题的答案进行操作 - 传递 Angular2 应用程序的注入器并从该注入器获取服务。
  • 是的,这行得通!那么这有多糟糕呢? (如果我没听错的话,你在上面的问题中称之为“肮脏的黑客”)。我认为这会限制子类的可测试性和可重用性?
  • 它隐藏了使代码更难阅读的依赖关系。它违背了熟悉 Angular2 DI 工作原理的人的期望。它打破了生成静态代码以替换动态 DI 的离线编译,以提高性能并减少代码大小。

标签: angular typescript dependency-injection singleton


【解决方案1】:

这应该为这个问题提供一个解决方案,但在任何需要注入服务而不提供它作为构造函数参数的情况下也有帮助。

我在另一篇文章中看到了这个答案: Storing injector instance for use in components

您可以在 AppModule 类中配置 Angular Injector,然后在任何其他类中使用它(您可以从任何类访问 AppModule 的成员)。

在 AppModule 中添加:

export class AppModule { 
  /**
     * Allows for retrieving singletons using `AppModule.injector.get(MyService)`
     * This is good to prevent injecting the service as constructor parameter.
     */
    static injector: Injector;
    constructor(injector: Injector) {
        AppModule.injector = injector;
    }
}

然后在您的其他课程中,您可以执行以下操作(对于这个问题,将 MyService 替换为 Http):

@Injectable()
export class MyClass{
    private myService;

    constructor(){
        this.myService = AppModule.injector.get(MyService);
    }
}

这相当于使用:

constructor(private myService: MyService){}

【讨论】:

  • 成功了!就我而言:从另一个模块(不是懒惰的)获取服务并全部解析实例!谢谢大佬。
  • 要添加@ronenmiller 的建议,您可以将{ provide: Injector, useValue: AppModule.injector } 添加到 providers 数组中。完成后,您可以使用 Injector 类引用将 Injector 类直接注入到任何类构造函数中。 constructor(injector: Injector) {}
  • 当我在一个继承了一堆子类的超类中引用 AppModule 时,我得到了循环依赖。
  • 在我的情况下,AppModule.injector 是未定义的。我得到:无法读取未定义的属性“get”
  • 使用 Angular 9,这个 resipe 不起作用。我在类型 'typeof AppModule'.ts(2339) 上出现属性 'injector' 不存在错误。
猜你喜欢
  • 2018-12-03
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 2016-04-28
  • 1970-01-01
  • 2020-06-27
  • 2019-04-20
  • 1970-01-01
相关资源
最近更新 更多