寻找 Dagger 辅助注射的示例 [英] Looking for an example for Dagger assisted injection

查看:22
本文介绍了寻找 Dagger 辅助注射的示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自 dagger-discuss@:>

我有一个类从对象图中获取一些依赖项,并在运行时从调用者获取其他依赖项.

公共类 ImageDownloader {//从注入器中获取这些依赖项.私人最终 HttpClient httpClient;私人最终 ExecutorService executorService;//从调用者那里获取这些.私有最终 URL imageUrl;私人最终 ImageCallback 回调;...}

我想出了一个解决方案,在那里我定义了一个工厂,

公共类 ImageDownloader {...公共静态类工厂{私人最终 HttpClient httpClient;私人最终 ExecutorService executorService;@注入公共工厂(HttpClient httpClient,ExecutorService executorService){this.httpclient = httpClient;this.executorService = executorService;}公共 ImageDownloader 创建(URL imageUrl,ImageCallback 回调){返回新的 ImageDownloader(httpClient, executorService, iamgeUrl, callback);}}...}

现在,我不再在客户端的构造函数中注入 ImageDownloader,而是简单地注入 ImageDownloader.Factory 并调用它的 create() 方法.

如您所见,这非常冗长且冗长.它还有一堆重复和样板.使用 @Inject 注释字段本身存在一些障碍,所以我们暂时忽略这种可能性.

Square 人提出了一个有趣的解决方案,即使用提供商.定义一个Factory接口,

公共类 ImageDownloader {...公共接口工厂{ImageDownloader create(URL imageUrl, ImageCallback 回调);}}

然后在一个模块中提供它,

公共类 ImageModule {...@提供public ImageModule.Factory provideImageModuleFactory(最终提供者httpClientProvider,最终提供者<ExecutorService>executorServiceProvider) {返回新的 ImageDownloader.Factory() {公共 ImageDownloader 创建(URL imageUrl,ImageCallback 回调){返回新的 ImageDownloader(httpClientProvider.get(), executorServiceProvider.get(),imageUrl, 回调);}}...}

(再次来自 dagger-discuss@).

我的 ImageDownloader 是一个类注入的类,该类注入了另一个类,而另一个类注入了另一个类,...,在 @Module.这一切以某种方式*有效,并且所有类都在构建时找到.现在,要添加一个模块,我必须明确地让对象图知道它.

我一定遗漏了一些东西 - 注入一个新类很容易,但添加一个新模块很乏味.

我的问题是:辅助注射在实践中是如何进行的?有人有例子吗?我应该如何使用 ImageModule,如果有的话?

* - 不知何故"确实暗示它对我来说有一定的魔力.

解决方案

因此,Google 的一些 Dagger/Guice 人员创建了一个名为 AutoFactory (http://github.com/google/auto) 在一个包含 AutoFactory(代码生成的辅助注入)、AutoValue(代码生成的自定义值类型)和 AutoService(Java 服务的自动生成)的项目中元数据文件).

AutoFactory 几乎按照您的预期运行 - 它会生成您本来可以手动创建的工厂.这是一个非常早期的版本,我们计划有更多的灵活性,但它会生成一个工厂类,该类将采用包含一些 JSR-330 可注入依赖项和一些调用堆栈参数的类型,并将它们合并在一起以创建实例带注释的类型.

本质上,如果您正确注释工厂创建的类型,它将自动生成您编写的工厂.

例如,如果您创建类:

@AutoFactory公共类 ImageDownloader {//从注入器中获取这些依赖项.私人最终 HttpClient httpClient;私人最终 ExecutorService executorService;//从调用者那里获取这些.私有最终 URL imageUrl;私人最终 ImageCallback 回调;图片下载器(@Provided HttpClient httpClient,@Provided ExecutorService executorService,ImageCallback 回调,网址 imageUrl) {//赋值}}

AutoFactory 将生成:

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")公共最终类 ImageDownloaderFactory {私有最终提供者<ExampleClasses.HttpClient>httpClientProvider;私有最终提供者<java.util.concurrent.ExecutorService>执行者服务提供者;@注入公共 ImageDownloaderFactory(提供者httpClientProvider,提供者executorServiceProvider) {this.httpClientProvider = httpClientProvider;this.executorServiceProvider = executorServiceProvider;}公共 ImageDownloader 创建(ImageCallback 回调,URL imageUrl){返回新的 ImageDownloader(httpClientProvider.get(),executorServiceProvider.get(),打回来,图片网址);}}

(注意,我们对输出源做了很多清理工作,但上面基本上是生成的内容,虽然格式不太好.)

结果类就是一个符合 JSR-330 的可注入类,你可以将它注入你的依赖图中(在 Dagger 或 Guice 中),它会为你创建这些对象,将调用堆栈状态与适当地提供依赖项.

您可以注入上述 Just-In-Time,也可以在闲暇时通过 @Provides 方法提供.

你甚至可以让工厂实现一个工厂接口,然后像这样简单地将两者绑定到一个 dagger 模块中:

@AutoFactory(implementing = MyFactoryInterface.class)公共类 ImageDownloader {//... 否则如上...}@模块(...)类我的模块{@Provides MyFactoryInterface factoryImpl(ImageDownloaderFactory impl) {返回实现;}}

From dagger-discuss@:

I have a class that gets some dependencies from the object graph, and other dependencies from a caller at runtime.

public class ImageDownloader {
  // Get these dependencies from the injector.
  private final HttpClient httpClient;
  private final ExecutorService executorService;

  // Get these from the caller.
  private final URL imageUrl;
  private final ImageCallback callback;

  ...
}

I came up with a solution, where I define a Factory,

public class ImageDownloader {
  ...
  public static class Factory {
    private final HttpClient httpClient;
    private final ExecutorService executorService;

    @Inject
    public Factory(HttpClient httpClient, ExecutorService executorService) {
      this.httpclient = httpClient;
      this.executorService = executorService;
    }

    public ImageDownloader create(URL imageUrl, ImageCallback callback) {
      return new ImageDownloader(httpClient, executorService, iamgeUrl, callback);
    }
  }
  ...
}

Now, instead of injecting ImageDownloader in the client's constructor, I simply inject ImageDownloader.Factory and call its create() method.

As you can see, that's quite verbose and long. It also has a bunch of duplication and boilerplate. There're some obstacles to annotating the fields themselves with @Inject, so let's ignore this possibility for now.

The Square people have come up with an interesting solution, using providers. Define a Factory interface,

public class ImageDownloader {
  ...
  public interface Factory {
    ImageDownloader create(URL imageUrl, ImageCallback callback);
  }
}

and then provide it in a module,

public class ImageModule {
  ...
  @Provides 
  public ImageModule.Factory provideImageModuleFactory(
      final Provider<HttpClient> httpClientProvider, 
      final Provider<ExecutorService> executorServiceProvider) {
    return new ImageDownloader.Factory() {
      public ImageDownloader create(URL imageUrl, ImageCallback callback) {
        return new ImageDownloader(httpClientProvider.get(), executorServiceProvider.get(),
            imageUrl, callback);
      }
  }
  ...
}

(again, from dagger-discuss@).

My ImageDownloader is a class that's injected by a class which is injected by another class which is injected by yet another class, ..., which is referenced in a @Module. This all somehow* works, and all classes are found in build time. Now, to add a module, I have to explicitly let the object graph know about it.

I must be missing something - it's very easy to inject a new class, but very tedious to add a new module.

My question is: how is assisted injection done in practice? anyone has an example? how should I use ImageModule, if at all?

* - "somehow" does indeed imply it's partly magic to me.

解决方案

So, some of the Dagger/Guice folks at Google created a thing called AutoFactory (http://github.com/google/auto) in a project that includes AutoFactory (code-generated assisted injection), AutoValue (code-generated custom value types) and AutoService (auto-generation of java services metadata files).

AutoFactory pretty much operates like you would expect - it generates the factory you would otherwise have hand-rolled. It's a very early version, and we have a lot more flexibility planned, but it will generate a factory class that will take a type that includes some JSR-330 injectable dependencies and some call-stack parameters, and merge them together in creating instances of the annotated type.

In essence it will generate the factory you wrote, automatically if you properly annotate your factory-created type.

For instance, if you create your class:

@AutoFactory
public class ImageDownloader {
  // Get these dependencies from the injector.
  private final HttpClient httpClient;
  private final ExecutorService executorService;

  // Get these from the caller.
  private final URL imageUrl;
  private final ImageCallback callback;

  ImageDownloader(
      @Provided HttpClient httpClient,
      @Provided ExecutorService executorService,
      ImageCallback callback,
      URL imageUrl) {
    // assignments
  }
}

AutoFactory will generate:

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class ImageDownloaderFactory {
  private final Provider<ExampleClasses.HttpClient> httpClientProvider;
  private final Provider<java.util.concurrent.ExecutorService> executorServiceProvider;

  @Inject
  public ImageDownloaderFactory(
      Provider<ExampleClasses.HttpClient> httpClientProvider,
      Provider<java.util.concurrent.ExecutorService> executorServiceProvider) {
    this.httpClientProvider = httpClientProvider;
    this.executorServiceProvider = executorServiceProvider;
  }

  public ImageDownloader create(ImageCallback callback, URL imageUrl) {
    return new ImageDownloader(
        httpClientProvider.get(), 
        executorServiceProvider.get(), 
        callback, 
        imageUrl);
  }
}

(Note, we have a bunch of clean-up to do on the output source, but the above is basically what is generated, though not quite as nicely formatted.)

The resulting class is then, properly a JSR-330 compliant injectable class, which you can inject in your dependency graph (in Dagger or Guice) and it will create these objects for you, co-mingling the call-stack state with the provided dependencies appropriately.

You can inject the above Just-In-Time, or you can provide it via an @Provides method at your leisure.

You can even have the factory implement a factory interface, and then simply bind the two together in a dagger module like so:

@AutoFactory(implementing = MyFactoryInterface.class)
public class ImageDownloader {
  // ... otherwise as above...
}

@Module(...)
class MyModule {
  @Provides MyFactoryInterface factoryImpl(ImageDownloaderFactory impl) {
    return impl;
  }
}

这篇关于寻找 Dagger 辅助注射的示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆