开篇
@Inject
的字面含义为“注入”,它的作用有两个:①表达依赖注入诉求②提供依赖
表达依赖诉求
①标记Field
@Inject
修饰一个类的Field
,即表示向dagger框架表达注入诉求,要求获得一个该Field
的实例。dagger框架将负责创建对象并赋予该Field
。
public class SuperMarket {
@Inject
protected Apple apple;
public SuperMarket() {
}
}
上面的代码,SuperMarket
的成员变量apple
被@Inject
修饰后,dagger框架将负责创建一个Apple
实例并赋值给apple
。点击android studio的绿色锤子编译一下,看一下这一步dagger为我们做了什么。
你会发现dagger为SuperMarket
生成了一个类:SuperMarket_MembersInjector
源码如下,
public final class SuperMarket_MembersInjector implements MembersInjector<SuperMarket> {
private final Provider<Apple> appleProvider;
public SuperMarket_MembersInjector(Provider<Apple> appleProvider) {
this.appleProvider = appleProvider;
}
public static MembersInjector<SuperMarket> create(Provider<Apple> appleProvider) {
return new SuperMarket_MembersInjector(appleProvider);
}
@Override
public void injectMembers(SuperMarket instance) {
injectApple(instance, appleProvider.get());
}
@InjectedFieldSignature("com.example.daggersample.SuperMarket.apple")
public static void injectApple(SuperMarket instance, Apple apple) {
instance.apple = apple;
}
}
实际上,一个类在表达依赖诉求后,dagger会为其生成一个成员注入器,命名规则依赖诉求方类名_MembersInjector
,如SuperMarket_MembersInjector
。
首先,成员注入器为会为依赖诉求方每一个需要注入的Field生成一个static的注入方法,如SuperMarket_MembersInjector
为SuperMarket.apple
生成了injectApple
方法。该方法接受依赖诉求方(SuperMarket)和待注入的对象(Apple)为参数,进行注入操作,也就是简单的赋值操作。
另外,注入器还会生成一个injectMembers
的实例方法,该方法接受依赖诉求方为参数,内部依次调用每个Field
的静态注入方法完成注入。其中待注入的对象由每个Field
的Provider<T>
提供,如Provder<Apple>
。Provider<T>
是一个泛型接口,只有一个get
方法,负责提供一个T
型实例。创建注入器对象时,会传入每个Field
对应的Provider<T>
。
总结来看,成员注入器本身并不负责生成待注入的对象,只负责简单的注入操作而已。dagger框架既可以直接通过静态注入方法为依赖诉求方注入成员,也可以创建注入器实例并传入对应成员的Provider,然后调用injectMembers
方法进行注入。至于何时采用静态方法,何时采用injectMembers
,下一篇:Dagger2系列详解(二):@Component注解揭晓。
注意,apple
的访问限制符不可以为private
,否则编译报错,因为dagger框架无法访问到它。
②标记方法
下面两种情况,@Inject
标记Field的方式无法表达依赖注入诉求,
- 基于不想破坏
Field
的封装性等原因,需要为Field添加private
访问控制符 Field
由父类(第三方类)继承而来,无法为其添加@Inject
注解,甚至子类没有访问Field
的权限,只能通过getter/setter
方法访问
此时,我们可以先自定义一个方法,方法名任意,形参为Field
对应类型,然后用@Inject
标记该方法。例如,
public class SuperMarket {
private Apple apple;
public SuperMarket() {
}
/**
* 该方法为dagger框架调用,并传入待注入的实例,故不可为private修饰,笔者注释
*/
@Inject
public void oneAppleInto(Apple apple) {
//这里直接访问apple为其赋值
//假如apple由于父类继承而来,而子类又没有访问权,可以通过Field的setter为其赋值
//笔者注释
this.apple = apple;
}
}
看一下,dagger生成的SuperMarket_MembersInjector
和之前有何不同。
public final class SuperMarket_MembersInjector implements MembersInjector<SuperMarket> {
...
@Override
public void injectMembers(SuperMarket instance) {
injectOneAppleInto(instance, appleProvider.get());
}
public static void injectOneAppleInto(SuperMarket instance, Apple apple) {
instance.oneAppleInto(apple);
}
}
你会发现,SuperMarket.apple
的静态注入方法变成了inject + 依赖诉求方标记的方法名
,并且内部通过诉求方标记的方法进行注入操作。
提供依赖
@Inject
修饰一个类的构造方法,即告知dagger:当需要为诉求方注入该类的实例时,可以调用该构造方法获取该类的实例然后注入。
public class Apple {
@Inject
public Apple() {
}
}
编译一下,看看会发生什么,
dagger为Apple
生成了一个工厂类Apple_Factory
,
public final class Apple_Factory implements Factory<Apple> {
@Override
public Apple get() {
return newInstance();
}
public static Apple_Factory create() {
return InstanceHolder.INSTANCE;
}
public static Apple newInstance() {
return new Apple();
}
private static final class InstanceHolder {
private static final Apple_Factory INSTANCE = new Apple_Factory();
}
}
工厂类的命名规则依赖提供方_Factory
,内部类InstanceHolder
缓存了工厂类实例,每次调用工厂类的get方法,他都会调用依赖提供方Apple中用@Inject标注的构造方法构建一个新的实例并返还给调用方。
结语
现在我们知道了:
-
@Inject标记一个类的Field或Method意为向dagger表达依赖注入请求。dagger将为其生成一个成员注入器(MembersInjector)负责注入操作,但本身并不负责创建要注入的实例,由注入器的调用方直接提供。
-
@Inject标记一个类的构造方法后,dagger将为其生成一个工厂类,工厂类负责生产该实例以对外提供依赖。
那么,谁负责生产实例(调用工厂方法或构造器),然后再调用成员注入器把这些实例注入依赖诉求方呢?答案是@Component
。