我熟悉传统设计模式中的依赖倒置原则,在这种模式中,您有一个抽象产品,它在请求工厂方法的类中执行任务。但依赖注入的不同之处在于它使用注释来生成产品。
我正在审核这个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类型的新泵?
答案 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型泵?“
我的答案:这是对的。