Dagger是基于Guice的开源依赖项注入(DI)框架。 但是,Dagger的开发人员对Guice的基本原理并不满意:他们一次又一次地不得不在较大的项目中编写代码,其中涉及大量的绑定代码。 由于这是静态语义的一部分,因此他们的策略是提取此绑定并将其以源代码形式存储。

Dagger开发人员还需要易于阅读且支持调试过程的内容。 下面我们更加仔细地研究Dagger并开始探索该框架。 我们的示例基于Dagger 1.2版

用Dagger进行依赖注入

Dagger的怪癖之一是其在Java和Android系统中的可用性。 让我们看一个简单的示例,并从Main类中的一个简单@Inject实例( Main Service )开始:

public class Main {
  @Inject MainService mainService;
  /..
}
public interface MainService {
  public String execute(String txt);
}
public class MainServiceImpl implements MainService {
  public String execute(String txt){
    return "MainServiceImpl _ " + txt;
  }
}

为了获得具有注入属性的类的实例,需要使用ObjectGraphObjectGraph是实例化所需的所有依赖项的表示。 在以下示例中,我们可以在Main类中看到Dagger的初始化和使用:

public class Main {
 @Inject MainService mainService;

  public static void main(String[] args) {
    //bootstrapping
    ObjectGraph objectGraph
        = ObjectGraph.create(new BusinessModule());
    Main main = objectGraph.get(Main.class);
//    Main main = new Main();
//    objectGraph.inject(main);
    System.out.println("execute = " + main.mainService.execute("Go"));
    System.out.println("execute = " + main.mainService.execute("Go"));
    System.out.println("execute = " + main.mainService.execute("Go"));
  }
}

Dagger通过两种方式访问​​包含注入的属性的类的实例。 一种方法是通过ObjectGraph类的get(..)方法直接提供一个就绪实例。 另一种方法是通过显式调用方法inject(..) ,该方法可以应用于现有实例。 这使您可以控制在生成保留类实例与成员本身之间的时间。

注意事项:为了生成ObjectGraph类的实例,需要create(..)方法的参数或模块。 在我们的例子中,我们创建了BusinessModule() 。 在此模块中,定义了它们之间的依赖关系,还使用了生产者。

@Module(library = false, injects = {Main.class}, complete = true)
public class BusinessModule {
  @Provides
  MainService provideMainService() {
    return new MainServiceImpl();
  }
}

生产者可以在实例本身中生成,也可以在方法参数上使用注入(如下)。 请注意,Dagger必须使用新的构造函数-如果要创建的实例本身没有注入的属性-或已通过带有注入属性的方法参数传递了实例。

@Provides
MainService provideMainService(MainServiceImpl mainService) {
  return mainService;
}

内部功能

开发人员很快就会提出的基本问题涉及到依赖项的定义。 Java中有几种定义依赖关系的方法-如果依赖关系很明确,则通常很容易。 当涉及区别或多重性时,它将变得更加复杂。

以类似SubService的接口为例。 对于此接口,有两种实现: SubServiceASubServiceB 。 如果我们将@Inject SubService放在源代码中,则实现不清楚。 在下文中,我们假定它将始终生成一个实例,该实例已通过注释@Produces管理了相应的方法ProvideXXX (在我们的示例中为offerMainService() )。 这是工厂方法。

public class MainServiceImpl implements MainService {
  @Inject SubService subService;
  public String execute(String txt){
    return subService.work(txt);
  }
}

还需要一种用于创建SubService实例的工厂方法。 在这里,您可以选择应使用的实现( SubServiceA或 SubServiceB )。 当然,这是一个静态的决定。 在稍后的阶段,我们将使其动态化。

@Provides
SubService provideSubService() {
  return new SubServiceA();
}

反射和配置

但是Dagger可以识别在哪里使用哪个实例吗? 反射或配置是这里的答案。 在某些框架中,使用配置方法。 然后读取此配置,并将其用作实例化的基础。 不幸的是,由于这些方法麻烦且容易出错,因此可能会出现问题。

另一种选择是反射。 在运行时,我们可以确定哪个类具有依赖关系,但是,在这种情况下,我们尚未解决多重性问题。 为此,JSR-330具有限定符@Named(..) 。 这将允许您输入相应的实现名称,然后在解析中使用它们。 SubServiceA将被实现为@Named(“A”),并用@Named SubServiceB(“B”)。 一旦指定了限定词,我们就定义了@Inject

@Inject @Named("A") SubService subservice;

@Named(“ A”)也提供了随附的工厂方法。 这是关于将类/接口和注释结合在一起,然后进行匹配的所有内容:

@Inject SubService subservice

您不要忘记,仍然需要编写没有限定符的工厂方法。

@Module(library = false, injects = {Main.class},complete = true)
public class BusinessModule {
  @Provides
  MainService provideMainService(MainServiceImpl mainService) {
    return mainService;
  }
  @Provides @Named("A")
  SubService provideSubServiceA() {
    return new SubServiceA();
  }
  @Provides @Named("B")
  SubService provideSubServiceB() {
    return new SubServiceB();
  }
  @Provides
  SubService provideSubService(@Named("A") SubService subServiceA) {
    return subServiceA;
  }
}

现在如何以及何时检测到依赖关系? 这可以使用反射在运行时完成。 Dagger是一个略有不同的框架:使用了反射,但它不是运行时,而是参与了编译过程。 使用反射解决依赖关系并进行检查,此过程会产生不同的结果。 首先,应用带有扩展的文件,您可以在其中阅读有关找到的依赖项的信息。 请参阅以下内容:

digraph G1 {
  concentrate = true;
  Main -> MainService;
  MainService -> MainServiceImpl;
  MainServiceImpl -> SubService;
  n2 [label="@javax.inject.Named(value=A)
           /org.rapidpm.demo.dagger.business.subservice.SubService"];
  SubService -> n2;
}

这些化合物易于识别。 但是生成了哪些类? 这是指: Main $$ InjectAdapterMainServiceImpl $$ InjectAdapterBusinessModule $$ ModuleAdapter

让我们从Main $$ InjectAdapter类开始。 适配器提供了一个get()方法,该方法返回一个已实例化的引用。 在这里,您可以看到确切的生命周期-而且很容易管理。 它包括两个步骤:首先,创建实例,其次, 合并injectMembers(..)方法。

此外,该化合物还适用于其他类别。 为了确保所有内容都保持静态语义,并在运行时调用相应的Getter。 与Reflection相比,此方法在运行时效率更高。 因此,此适配器类形成了完整的绑定,其中包括应用程序的所有组合和变体。

翻译自: https://jaxenter.com/dependency-injection-dagger-113803.html

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐