繁体   English   中英

有没有办法访问以前创建的 Guice 注入器?

[英]Is there a way to access Guice injectors which have previously been created?

为一个新项目查看 Guice(和 Dagger)。 到目前为止,我看到的每个 Guice 教程都显示了在开发人员需要 DI 来创建对象实例时创建的注入器。

网上看到的一个典型例子:

public static void main(String[] args) {
    Injector injector = Guice.createInjector(new BasicModule());
    Communication comms = injector.getInstance(Communication.class);
}

对我来说,这违背了 DI 的目的——在任何需要实例的地方,你将实例绑定到定义如何构建它的模块。

有没有办法让 Guice 创建一个类的实例,该类的模块(依赖图)之前已经定义给 Guice(例如,在应用程序启动时?)。

我正在使用 Dropwizard.io 框架,因此在某些情况下,我无法完全控制类的构造方式,但希望能够模拟我在该类中引用的依赖项。

完全相同的适用于 Dagger - 我很欣赏其中一个/两个的示例。

编辑:多年来,我在 .NET 中使用过几个 DI 框架,所以我将举例说明我正在尝试基于其中一个框架做什么。

例如,在 ASP.NET Core DI 实现中,在服务启动时定义您希望 DI 能够创建的服务。 通常你会要求 DI 给你一个实例,它是一个接口的实现。 所以在启动时:

protected override void ConfigureAdditionalServices(IServiceCollection services)
{
    services.AddScoped<ITransactionService, TransactionService>();
}

其中IServiceCollection是定义给 DI 的服务集合。

因为 DI 与 ASP.NET 框架集成,从这一点开始,您通常可以定义一个接受ITransactionService的构造函数,DI 将为您提供它。

但是,如果您在不知道它的框架中使用 DI,则需要访问当前的 ServiceProvider 实例,然后您可以要求 DI 创建您的对象,如下所示:

var transactionService = ServiceProvider.GetService<ITransactionService>();

我意识到这实现了Service Locator 反模式,但它仍然具有将我的代码与具体类实现解耦的好处,并允许我在应用程序启动时模拟它们以进行测试。

所以回到问题所以根据这种情况重申我的问题,我如何在我的代码中的某个随机点从 Guice 请求一个类?

我需要在此代码中更改哪些内容才能使其正常工作?

public class TransactionModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(TransactionServiceBase.class).to(TransactionService.class);
  }
}

// At startup
Injector injector = Guice.createInjector(new TransactionModule());


// Then, somewhere in the application, to get an instance of TransactionService
TransactionServiceBase transactionService = (TransactionServiceBase)Guice.getInstance(TransactionServiceBase.class);

我认为您可能会误解 Injector.getInstance - 就像您的示例有一个public static方法来开始一样,即使您通常不会使用所有公共静态方法编写应用程序的其余部分(我希望),除了在极少数特定情况下,您也不会调用Injector.getInstance

相反,此代码仅用于使事情顺利进行。 另一个流行的“开始”是injector.injectMembers(this) - 让main()手动创建一个实例,该实例是您的应用程序的基础,带有@Inject注释的成员,然后只要求现在创建的 Injector填充成员。

当您继续“向内”应用程序的其余部分时,您可能永远不会再次引用 Injector 实例,而是依赖提供程序、辅助注入或只是 guice 创建的实例。

通过这种方式,您永远不应该关心注入器或为其设置的确切模块。 在应用程序的整个生命周期内应该只存在一个注入器(基本上没有例外,除非您重新定义“应用程序”是什么),并且在 99% 的时间里它对您隐藏(例外:您的 DI满足其他一些 DI,并且需要通过其类请求某事物的实例,或者您有工具想要内省所有声明的绑定集)。 因此,您应该能够只提供 setter、构造函数 args 或 init 方法,然后可以手动调用它们,或者让任何 guice 上下文根据它们自己的特定模块和规则创建它们。

我认为答案是没有标准/支持的方法来做到这一点。

通常的假设是你有尽可能少的“注入”点,最好是一个,然后你通过创建依赖项构造函数参数来指定每个类需要什么。

我所知道的与您在此处描述的情况类似的唯一场景是 android 应用程序中的 Dagger。 他们解决这个问题的方法是将匕首“注入器”(sorta)存储在一个全局对象 - 应用程序中,然后 Dagger 提供一个静态函数来检索该对象并执行注入。

长话短说 DI 框架不适用于您自己不实例化类的范式。

我能想到的唯一解决方案是将您的注入器存储在某个全局变量中,并在您需要时从那里获取它。

静态注入可能对您的情况有所帮助https://github.com/google/guice/wiki/Injections#static-injections

暂无
暂无

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

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