use*_*136 19 java dependency-injection assisted-inject dagger
来自匕首讨论@:
我有一个类从对象图中获取一些依赖项,并在运行时从调用者获取其他依赖项.
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;
...
}
Run Code Online (Sandbox Code Playgroud)
我提出了一个解决方案,在那里我定义了一个工厂,
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);
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
现在,ImageDownloader我只是注入ImageDownloader.Factory并调用其create()方法,而不是注入客户端的构造函数.
正如你所看到的那样,这是非常冗长和冗长的.它还有一堆重复和样板.用字段注释字段本身存在一些障碍@Inject,所以现在让我们忽略这种可能性.
Square人们使用提供商提出了一个有趣的解决方案.定义一个Factory界面,
public class ImageDownloader {
...
public interface Factory {
ImageDownloader create(URL imageUrl, ImageCallback callback);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在一个模块中提供它,
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);
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
(再次,来自dagger-discuss @).
我ImageDownloader是一个由一个类注入的类,该类由另一个类注入,该类由另一个类注入,...,在a中引用@Module.这一切都以某种方式*起作用,所有类都在构建时间中找到.现在,要添加模块,我必须明确地让对象图知道它.
我必须遗漏一些东西 - 注入一个新类很容易,但添加一个新模块非常繁琐.
我的问题是:如何在实践中完成辅助注射?谁有一个例子?ImageModule如果有的话我应该如何使用?
* - "某种程度上"确实意味着它对我来说是部分魔力.
Chr*_*ber 17
因此,谷歌的一些Dagger/Guice人员在一个包含AutoFactory(代码生成的辅助注入),AutoValue(代码生成的自定义值)的项目中创建了一个名为AutoFactory(http://github.com/google/auto)的东西.types)和AutoService(自动生成java服务元数据文件).
AutoFactory几乎可以像您期望的那样运行 - 它会生成您手工轧制的工厂.这是一个非常早期的版本,我们计划了更多的灵活性,但它将生成一个工厂类,它将采用包含一些JSR-330可注入依赖项和一些调用堆栈参数的类型,并在创建实例时将它们合并在一起带注释的类型.
实质上,如果您正确注释工厂创建的类型,它将自动生成您编写的工厂.
例如,如果您创建了您的类:
@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
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
(注意,我们在输出源上有一堆清理工作,但上面基本上是生成的,但格式不是很好.)
然后,生成的类是一个JSR-330兼容的可注入类,你可以在你的依赖图(Dagger或Guice)中注入它,它将为你创建这些对象,将调用堆栈状态与提供的依赖关系混合在一起适当.
您可以注入上述即时,或者您可以通过@Provides休闲方式提供.
您甚至可以让工厂实现工厂接口,然后简单地将两者绑定在一个匕首模块中,如下所示:
@AutoFactory(implementing = MyFactoryInterface.class)
public class ImageDownloader {
// ... otherwise as above...
}
@Module(...)
class MyModule {
@Provides MyFactoryInterface factoryImpl(ImageDownloaderFactory impl) {
return impl;
}
}
Run Code Online (Sandbox Code Playgroud)
正如@xsveda 所说,对于辅助注射,您可能想要使用AssistedInject。我在这篇博文中写过它,但我会在这里添加一个完整的例子,让事情变得更容易。
您需要的第一件事是依赖项:
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0'
Run Code Online (Sandbox Code Playgroud)
那么您的示例如下所示:
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
}
}
Run Code Online (Sandbox Code Playgroud)
首先@Inject,我们不是用 注释构造函数,而是用 注释它@AssistedInject。然后我们注释必须经过工厂的参数,这与 AutoFactory 期望的相反。最后,我们需要一个带有注释的内部工厂接口,@AssistedInject.Factory它有一个接收辅助参数并返回我们感兴趣的实例的方法。
不幸的是,我们在这里还有一个额外的步骤:
@AssistedModule
@Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule
Run Code Online (Sandbox Code Playgroud)
我们不一定需要一个专门的模块,即使这是一个有效的选择。但是我们也可以在组件中已经安装的另一个模块中使用这些注释。这里的好处是我们只需要做一次,之后任何工厂都会自动成为图表的一部分。
有了它,您基本上可以像往常一样注入工厂并请求您的对象。
| 归档时间: |
|
| 查看次数: |
6410 次 |
| 最近记录: |