寻找 Dagger 辅助注射的示例 [英] Looking for an example for Dagger assisted injection
问题描述
来自 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屋!