Dagger
为Android和Java打造的依赖注入框架
简介
略
使用Dagger
我们将使用一个咖啡机的例子来展示依赖注入和Dagger。
声明依赖
Dagger创建一个你的应用的实例并且满足他们的依赖。它使用javax.inject.Inject 注解来标明哪个构造函数或者成员属性是它感兴趣的。
使用@Inject
来注解一个Dagger用来创建一个实例的构造方法。当一个新的实例被申请的时候,Dagger就会获取到请求参数值并且调用构造方法。
class Thermosiphon implements Pump {
private final Heater heater;
@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
...
}
Dagger也可以直接注入属性。下面这个例子直接为pump属性和heater属性分别获取了一个实例。
class CoffeeMaker {
@Inject Heater heater;
@Inject Pump pump;
...
}
如果你的类只有被 @Inject 标注的属性,但是却没有被其标注的构造方法,Dagger将使用无参构造方法(如果它存在的话)。缺少@Inject标注的类不能被Dagger构建。
Dagger不支持方法注入。
满足依赖
一般来讲,Dagger会使用上述方式来构造一个对应请求类型的实例,以此来满足依赖。当你请求了一个CofferMaker,将会调用new CofferMaker()并把它关联到属性中。
但是 @Inject 不能在以下情况工作:
- 接口不能被构造
- 第三方类不能被构造
- 要注册的对象必须已经标注过!
在这种情况下尴尬的情况下,可以使用 @Provides 注解一个方法来满足依赖。方法的返回值定义了它将满足的依赖。
举个例子,provideHeater()将在Heater被请求时调用:
@Provides Heater provideHeater() {
return new ElectricHeater();
}
被@Provides标注的方法也有可能有他们自己的依赖。当请求一个Pump的时候,这个方法返回一个 Thermosiphon 。
@Provides Pump providePump(Thermosiphon pump) {
return pump;
}
所有的 @Provides的方法属于module。这是一个被@Module标注的类:
@Module
class DripCoffeeModule {
@Provides Heater provideHeater() {
return new ElectricHeater();
}
@Provides Pump providePump(Thermosiphon pump) {
return pump;
}
}
依照惯例,@Provides方法一般会有一个provide前缀,Module类一般会有一个Module后缀。
创建图
被@Inject 和 @Provides标注的类之间的依赖关系,可以使用一个对象图来表示。可以使用ObjectGraph.create()
来获取这个图,其可以接收一个或者多个module。
ObjectGraph objectGraph = ObjectGraph.create(new DripCoffeeModule());
为了这个图能使用,我们需要去引导注入(bootstrap injection)。一般会在命令行程序中的main类中,或者在一个Android App的Activity中请求注入。在我们咖啡机的示例程序中,CoffeeApp类被用来启动依赖注入。我们让图来提供一个注入的示例:
class CoffeeApp implements Runnable {
@Inject CoffeeMaker coffeeMaker;
@Override public void run() {
coffeeMaker.brew();
}
public static void main(String[] args) {
ObjectGraph objectGraph = ObjectGraph.create(new DripCoffeeModule());
CoffeeApp coffeeApp = objectGraph.get(CoffeeApp.class);
...
}
}
只剩一件事还没做了,那就是图还不知道CoffeeApp类。我们需要像注册一个module一样显示地注册它:
@Module(
injects = CoffeeApp.class
)
class DripCoffeeModule {
...
}
注入操作将会在编译期就让图生效。以此来发现一些问题。(Detecting problems early speeds up development and takes some of the danger out of refactoring.)
现在图已经被建立起来,而且根对象也被注入了,我们来运行一下我们的咖啡机。好玩吧。
$ java -cp ... coffee.CoffeeApp
~ ~ ~ heating ~ ~ ~
=> => pumping => =>
[_]P coffee! [_]P