使用Dagger了解Java中的依赖注入

时间:2017-04-04 21:59:16

标签: java dependency-injection dagger-2

我熟悉传统设计模式中的依赖倒置原则,在这种模式中,您有一个抽象产品,它在请求工厂方法的类中执行任务。但依赖注入的不同之处在于它使用注释来生成产品。

我正在审核这个Dagger 2示例。这是最终结果:

// CoffeeApp.java
public class CoffeeApp {
  @Singleton
  @Component(modules = { DripCoffeeModule.class })
  public interface Coffee {
    CoffeeMaker maker();
  }

  public static void main(String[] args) {
    Coffee coffee = DaggerCoffeeApp_Coffee.builder().build();
    coffee.maker().brew();
  }
}

$ java -cp ... coffee.CoffeeApp
~ ~ ~ heating ~ ~ ~
=> => pumping => =>
 [_]P coffee! [_]P

我在这里理解这条线路时遇到了麻烦:

 CoffeeMaker maker();

在CoffeeMaker类中,没有make()方法。那么这是如何工作的?

这是我的理解:

CoffeeMaker类在其构造函数中使用@Inject批注:

@Inject CoffeeMaker(Lazy<Heater> heater, Pump pump) {
  this.heater = heater;
  this.pump = pump;
}

这将迫使Dagger在实例化CoffeeMaker时实例化一个新的加热器和一个新泵,这是正确的吗?或者只需要引用CoffeeMaker类本身?该文件说明了这一点:

  

当您申请CoffeeMaker时,它会通过调用new获得一个   CoffeeMaker()并设置其可注射的字段。

请求请求是什么意思?

当它说,它将设置其可注射的字段,我注意到加热器和泵是接口。有一个带有@Module注释的相应PumpModule类。它包含方法providePump

该文件说:

The method’s return type defines which dependency it satisfies.

这是否意味着当调用@Inject CoffeeMaker构造函数时,它会反过来发现泵参考并搜索PumpModule @Module,然后发现providePump并实例化一个Thermosiphon类型的新泵?

2 个答案:

答案 0 :(得分:1)

Dagger是编译时依赖注入解决方案。

接口CoffeeMaker maker()上的行CoffeeApp.Coffee,注释为,意味着Dagger将生成并编译具有实现的CoffeeApp.Coffee 的实现对于maker方法,它将为您提供完全注入的CoffeeMaker实例。如果您愿意,可以查看Dagger生成的文件DaggerCoffeeApp_Coffee.java,它看起来很像slide 41 of the original Dagger 2 talk上的实现。 (幻灯片35和36显示了Dagger写的相应工厂/提供商实现。)

  

这会迫使Dagger在实例化CoffeeMaker时实例化一个新的加热器和一个新泵,这是正确的吗?

是的,通常。虽然使用@Provides方法返回现有实例是您的特权,或者使用@Singleton之类的注释让Dagger管理现有实例,但Dagger默认行为是为每个依赖项创建一个新实例,并为该依赖项的每个依赖项创建一个新实例,等等。

  

这是否意味着当调用@Inject CoffeeMaker构造函数时,它会反过来发现泵参考并搜索PumpModule @Module,然后发现providePump并实例化一个Thermosiphon类型的新泵?

几乎正确:要生成该实现,Dagger将检查@Inject CoffeeMaker构造函数,发现CoffeeMaker需要加热器和泵,等等。对于像Guice这样的框架,这一切都发生在运行时,但对于Dagger而言,所有这些分析和映射都是在编译时发生的。在您的示例中,DripCoffeeModule中存在@Provides Pump方法,Dagger不会搜索该方法:该示例通过CoffeeApp.Coffee上的@Component注释提供它。

答案 1 :(得分:0)

@Donato,你说得对,CoffeeMaker没有maker()方法,Coffee接口确实有maker()方法。该方法(maker())返回类型为CoffeMaker的对象。因此,在您的示例中,DaggerCoffeeApp_Coffee.builder().build();将返回Coffee的实现,后者又实现maker()方法。

问题:请求请求是什么意思?

我的答案:请求意味着注入(即在@Inject的任何地方)。因此,例如,以下私有变量声明“请求”CoffeeMaker

的实例
public MyClass {
  @Inject private CoffeeMaker maker;
  ...
}

CoffeeMaker依次“请求”实例或Heater以及Pump的实例:

@Inject CoffeeMaker(Lazy<Heater> heater, Pump pump) {
  this.heater = heater;
  this.pump = pump;
}

因此,Heater的实例和Pump的实例将在实例化(或注入)maker时被实例化并注入。

问题:这是否意味着当调用@Inject CoffeeMaker构造函数时,它会反过来发现泵引用并搜索PumpModule @Module,然后发现providePump并实例化一个新的Thermosiphon型泵?

我的答案:这是对的。