依赖注入(五)—— Dagger的Lazy与Provider

2,260 阅读2分钟

Lazy

在Dagger中Lazy可以将要注入的依赖项转变为懒加载模式,这样注入的依赖项,只有在需要使用时,才会调用对应的依赖生成方法。懒加载的实现很简单,只需要在注入位置将依赖项的类型设置为Lazy接口的类型参数即可。

@Inject
@GsonType(value = "normal")
lateinit var gson: Lazy<Gson>

gson.get() // 调用get获取依赖项实例,第一次调用时才会执行依赖生成方法
gson.get() // 后续再调用,获取的是同一个实例

💡 在kotlin中使用Dagger时需要注意Lazy接口是dagger.Lazy,而不是kotlin.Lazy

实现原理

Dagger实现懒加载模式的原理是在执行依赖注入时,将对应的对象工厂对象使用DoubleCheck.lazy方法包装一下,返回一个DoubleCheck代理实例,而通过查看源码可知,DoubleCheck实现了Lazy接口。

public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<Gson> gsonProvider;

  @Override
  public void injectMembers(MainActivity instance) {
    injectGson(instance, DoubleCheck.lazy(gsonProvider));
  }
  ...
}

Provider

Provider是javax.inject包中提供的一个接口,Dagger对此接口也提供了支持,使用该接口可以直接依赖项的Provider对象,从而实现每次使用时都调用依赖提供方法获取新的对象的效果。Provider的使用和Lazy一样,也是只需要在注入位置将依赖项的类型设置为Provider接口的类型参数即可。

@Inject
@GsonType(value = "normal")
lateinit var gson: Provider<Gson>

gson.get() // 每次调用都会执行依赖生成方法,
gson.get() // 获取新的对象。

实现原理

我们知道,Dagger会在编译时为所有的依赖项生成对应的工厂类,并且在获取依赖项实例时,也是通过这个工厂类的实例来获取的。

public final class CommonModule_ProvideGsonFactory implements Factory<Gson> {
  private final CommonModule module;
  public CommonModule_ProvideGsonFactory(CommonModule module) {
    this.module = module;
  }
  @Override
  public Gson get() {
    return provideGson(module);
  }
  public static Student provideGson(CommonModule instance) {
    return Preconditions.checkNotNullFromProvides(instance.provideGson());
  }
  ...
}

工厂类实现自Factory接口,而Factory接口则继承了Provider接口:

public interface Factory<T> extends Provider<T> { }

当Dagger检测到要注入的依赖项是Provider接口的参数化实例时,就会直接注入该依赖项的工厂类实例,因此,当我们调用注入对象的get方法时,实际就是通过工厂实例间接调用了inject- constructorprovides-method

public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<Gson> gsonProvider;

  @Override
  public void injectMembers(MainActivity instance) {
    injectGson(instance, gsonProvider);
  }
  ...
}