Java 正在寻找匕首辅助注射的示例

Java 正在寻找匕首辅助注射的示例,java,dependency-injection,dagger,assisted-inject,Java,Dependency Injection,Dagger,Assisted Inject,发件人: 我有一个类,它从对象图中获取一些依赖项,并在运行时从调用方获取其他依赖项 public class ImageDownloader { // Get these dependencies from the injector. private final HttpClient httpClient; private final ExecutorService executorService; // Get these from the caller. private

发件人:

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

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;

  ...
}
我提出了一个解决方案,我定义了一个工厂

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);
    }
  }
  ...
}
现在,我不再在客户端的构造函数中注入
ImageDownloader
,而是简单地注入
ImageDownloader.Factory
并调用其
create()
方法

正如你所见,这是相当冗长的。它还有一堆复制品和样板。使用
@Inject
注释字段本身存在一些障碍,因此现在我们忽略这种可能性

Square的人提出了一个有趣的解决方案,使用提供者。定义一个
工厂
接口

public class ImageDownloader {
  ...
  public interface Factory {
    ImageDownloader create(URL imageUrl, ImageCallback callback);
  }
}
然后在模块中提供

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);
      }
  }
  ...
}
公共类图像模块{
...
@提供
公共图像模块。工厂提供的图像模块目录(
最终提供程序httpClientProvider,
最终提供者(服务提供者){
返回新的ImageDownloader.Factory(){
公共ImageDownloader创建(URL imageUrl、ImageCallback回调){
返回新的ImageDownloader(httpClientProvider.get(),executorServiceProvider.get(),
imageUrl,回调);
}
}
...
}
(同样,来自dagger讨论@)

My
ImageDownloader
是一个由另一个类注入的类注入的类,另一个类注入另一个类,…,在
@Module
中引用。这一切都以某种方式*起作用,所有类都在构建时找到。现在,要添加一个模块,我必须显式地让对象图知道它

我肯定遗漏了什么——注入一个新类非常容易,但添加一个新模块却非常乏味

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


*-“不知何故”的确意味着它对我来说有一定的魔力。

因此,谷歌的一些Dagger/Guice人员在一个项目中创建了一个名为AutoFactory()的东西,其中包括AutoFactory(代码生成的辅助注入)、AutoValue(代码生成的自定义值类型)和AutoService(自动生成java服务元数据文件)

AutoFactory的运行方式与您预期的非常相似-它生成了您本来可以手动运行的工厂。这是一个非常早期的版本,我们计划了更多的灵活性,但它将生成一个工厂类,该类将采用一种类型,包括一些JSR-330可注入依赖项和一些调用堆栈参数,并合并在创建带注释类型的实例时,将em组合在一起

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

例如,如果创建类:

@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将生成:

@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);
  }
}

您可以使用匕首进行辅助注射


请检查我在这里的原始答案:

正如@xsveda所说,对于辅助注射,您可能想使用。我在中写到了这一点,但我将在这里添加一个完整的示例,以使事情更简单

您首先需要的是依赖关系:

compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0'
下面是您的示例的样子:

class ImageDownloader @AssistedInject constructor(
  private val httpClient: HttpClient,
  private val executorService: ExecutorService,
  @Assisted private val imageUrl: URL,
  @Assisted private val callback: ImageCallback
) {

  @AssistedInject.Factory
  interface Factory {
    fun create(imageUrl: URL, callback: ImageCallback): ImageDownloader
  }
}
首先,我们不是用
@Inject
注释构造函数,而是用
@AssistedInject
注释它。然后我们注释必须经过工厂的参数,这与AutoFactory期望的相反。最后,我们需要一个用
@AssistedInject.com注释的内部工厂接口ry
具有一个方法,该方法接收辅助参数并返回我们感兴趣的实例

不幸的是,我们还有一个额外的步骤:

@AssistedModule
@Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule
我们不一定需要一个专用的模块,即使这是一个有效的选项。但我们也可以在另一个已经安装在组件中的模块中使用这些注释。这里的好处是,我们只需要执行一次,之后,任何工厂都将自动成为图形的一部分


有了它,你基本上可以像平常一样注入工厂并请求你的对象。

我在键入时发布了AutoFactory的0.1-beta1。谢谢你的指针!不过,我还是很好奇AI在实践中是如何实现的,并寻找一个例子。顺便问一句,有没有一种方法可以使用我的模块而不显式地将其添加到其他模块中,而不是在下面-我的控制模块?当然可以-我会对答案进行一点扩展。感谢您的澄清。但是,它并没有回答最初的问题,只是想在AutoFactory之前找到一个它现在是如何完成的示例。再次感谢!至于它在实践中是如何完成的,就我所看到的,它与AutoFactory是如何完成的,就像手工轧制的工厂一样。但它并不经常(现在)用匕首完成,因为没有人喜欢写样板,而且工具也不在那里。
@AssistedModule
@Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule