回顾
上一篇我们主要介绍了如何用Dagger2在Android应用中进行依赖注入, 在这一篇中, 我们主要来理解Dagger2中的原理, 毕竟知己知彼后才用得踏实
API关系
- Provider: provider是一个接口, 它的作用是包装被依赖的类
- Factory: 继承于Provider, 作用是创建依赖的对应实例
- MembersInjector: 也是一个接口, 作用是将依赖注入到需要依赖的地方, 其中的T为注入地点
理解上面的接口的作用后, 我们来理解Dagger2不会太难啦
Inject注入解读
我们利用上篇中的Demo来解读Inject注入. Dagger2生成的源代码可以在app目录下的build目录中的apt目录找到.
既然Component是注入依赖的桥梁, 那我们就先来看看它是怎么出入的吧. 回顾一下上次我们在StudentActivity注入的代码
1 2 3 4 5 6 7 8 9 10 11
| @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerStudentComponent.builder() .build() .inject(this); Toast.makeText(this, mStudent.name(), Toast.LENGTH_SHORT).show(); }
|
在onCreate方法中进行了注入, 仔细看注入的代码, 我们可以大概猜测是用Builder模式创建StudentComponenet实例, 既然这样, 我们先进入build()方法研究一波
1 2 3 4 5 6 7
| public static final class Builder { private Builder() {} public StudentComponent build() { return new DaggerStudentComponent(this); } }
|
在build()中, 实例了DaggerStudentComponent, DaggerStudentComponent是StudentComponent具体的实现类, 我们顺着思路, 进入DaggerStudentComponent看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public final class DaggerStudentComponent implements StudentComponent { private MembersInjector<StudentActivity> studentActivityMembersInjector; private DaggerStudentComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static StudentComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.studentActivityMembersInjector = StudentActivity_MembersInjector.create(Student_Factory.create()); } @Override public void inject(StudentActivity activity) { studentActivityMembersInjector.injectMembers(activity); }
|
上面的代码中, 主要调用了initialize方法进行初始化, 在其中, 创建了StudentActivity_MemberInjector实例
还记得我们在StudentActivity中调用了build()方法后, 还会调用inject(this)吗? 调用该方法后, 会调用我们刚刚在initialize方法中创建出来的StudentActivity_MemberInjector的injectMembers(activity), 我们看看对应的方法都干了什么事情
1 2 3 4 5 6 7
| @Override public void injectMembers(StudentActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.mStudent = mStudentProvider.get(); }
|
看到上面的代码, 有没有一种熟悉的感觉? instance.mStudent正是我们在StudentActivity中需要注入的成员变量, 而给它赋值的又是谁?
mStudentProvider变量是我们实例化StudentActivity_MemberInjector传进来的, 我们自然进入对应的类探究探究
1 2 3 4 5 6 7 8 9 10 11 12
| public final class Student_Factory implements Factory<Student> { private static final Student_Factory INSTANCE = new Student_Factory(); @Override public Student get() { return new Student(); } public static Factory<Student> create() { return INSTANCE; } }
|
StudentFactory中的get()方法返回了对应的Student实例
分析到这里, Inject注解已经完成了一次依赖注入, 因此我们来串联一下各个步骤吧
首先提供依赖的是Stduent_Factory类, 它是Factory的具体实现类, 给我们需要依赖的地方new出实例,
StudentActivity_MemberInjector, 它是MemberInjector的具体实现类, 它在injectMembers(StudentActivity中, 拿到我们需要依赖的实例, 并给被Inject标注的成员变量赋值, 而实例的来源正是我们刚才分析的
讲到这里, 我想大家都对Component的作用加深了, Component就像一座桥梁, 将提供依赖的工厂类, 和需要依赖的地方联系起来, 从而完成依赖注入
Moduley依赖注入
Module依赖注入的讲解, 我们也是用Student的Demo来讲解
1 2 3 4 5 6 7 8 9 10 11
| @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerStudentComponent.builder() .build() .inject(this); Toast.makeText(this, mStudent.name(), Toast.LENGTH_SHORT).show(); }
|
我们按照来老套路, 进入build()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public static final class Builder { private StudentModule studentModule; private Builder() {} public StudentComponent build() { if (studentModule == null) { this.studentModule = new StudentModule(); } return new DaggerStudentComponent(this); } public Builder studentModule(StudentModule studentModule) { this.studentModule = Preconditions.checkNotNull(studentModule); return this; } }
|
还是熟悉的套路, 只不过这次多了一个StduentModule变量, StudentModule是我们事先写好用于提供依赖的类, 我们可以看到在build()方法中, 实例化了StudentModule和DaggerStduentComponent, 又是老套路, 进入DaggerStduentComponent看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public final class DaggerStudentComponent implements StudentComponent { private Provider<Student> providesStudentProvider; private MembersInjector<StudentActivity> studentActivityMembersInjector; private DaggerStudentComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static StudentComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.providesStudentProvider = StudentModule_ProvidesStudentFactory.create(builder.studentModule); this.studentActivityMembersInjector = StudentActivity_MembersInjector.create(providesStudentProvider); } @Override public void inject(StudentActivity activity) { studentActivityMembersInjector.injectMembers(activity); }
|
跟我们上面分析Inject的代码差不多, 不同的是这次在initialize中创建的是StudentModule_ProvidesStudentFactory, 接下来的流程和Inject都差不多, 我们现在主要来分析StudentModule_providesStduentFactory怎么拿到依赖实例
1 2 3 4 5
| @Override public Student get() { return Preconditions.checkNotNull( module.providesStudent(), "Cannot return null from a non-@Nullable @Provides method"); }
|
在get()方法中, 利用module.providesStudent() 提供实例, 这个方法是我们事先在StudentModule中定义的
总体来说Module依赖注入的方式和Inject差不多, 只是提供依赖时生成的工厂方法不一样而已
分析完了Inject和Module注入, 我们来看看Name注解是如何解决依赖迷失,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Module public class StudentModule { @Named("student1") @Provides Student providesStudent() { return new Student(); } @Named("student2") @Provides Student proStudnet() { return new Student(); } }
|
我们make一下工程, 再到app->build->source->apt->debug目录下, 可以看看这两个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public final class StudentModule_ProvidesStudentFactory implements Factory<Student> { private final StudentModule module; public StudentModule_ProvidesStudentFactory(StudentModule module) { assert module != null; this.module = module; } @Override public Student get() { return Preconditions.checkNotNull( module.providesStudent(), "Cannot return null from a non-@Nullable @Provides method"); } public static Factory<Student> create(StudentModule module) { return new StudentModule_ProvidesStudentFactory(module); } public static Student proxyProvidesStudent(StudentModule instance) { return instance.providesStudent(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public final class StudentModule_ProStudnetFactory implements Factory<Student> { private final StudentModule module; public StudentModule_ProStudnetFactory(StudentModule module) { assert module != null; this.module = module; } @Override public Student get() { return Preconditions.checkNotNull( module.proStudnet(), "Cannot return null from a non-@Nullable @Provides method"); } public static Factory<Student> create(StudentModule module) { return new StudentModule_ProStudnetFactory(module); } public static Student proxyProStudnet(StudentModule instance) { return instance.proStudnet(); } }
|
相信聪明的你,已经知道Name注解解决的思路. 很简单, 就是每一个方法对应生成一个工厂类提供对应的依赖, 至于类的命名规则我就不说啦, 自己看
迷之Scope
Scope是作用域, Singleton是被Scope包装的一个注解, 在Dagger2中如果被Singleton标注的话, 该依赖可以在一定程度上实现单例 只不过这种单例是需要条件的, 这个条件是什么? 代码是最好的老师, 我们还是来看看被Sington标注的依赖会生成什么代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public final class DaggerStudentComponent implements StudentComponent { private Provider<Student> proStudnetProvider; private MembersInjector<StudentActivity> studentActivityMembersInjector; private DaggerStudentComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static StudentComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.proStudnetProvider = DoubleCheck.provider(StudentModule_ProStudnetFactory.create(builder.studentModule)); this.studentActivityMembersInjector = StudentActivity_MembersInjector.create(proStudnetProvider); } @Override public void inject(StudentActivity activity) { studentActivityMembersInjector.injectMembers(activity); } public static final class Builder { private StudentModule studentModule; private Builder() {} public StudentComponent build() { if (studentModule == null) { this.studentModule = new StudentModule(); } return new DaggerStudentComponent(this); } public Builder studentModule(StudentModule studentModule) { this.studentModule = Preconditions.checkNotNull(studentModule); return this; } } }
|
仔细观察上面代码, 我们看到唯一不同的provider赋值的时候, 多了一个DoubleCheck, 其中的奥妙
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| public final class DoubleCheck<T> implements Provider<T>, Lazy<T> { private static final Object UNINITIALIZED = new Object(); private volatile Provider<T> provider; private volatile Object instance = UNINITIALIZED; private DoubleCheck(Provider<T> provider) { assert provider != null; this.provider = provider; } @SuppressWarnings("unchecked") @Override public T get() { Object result = instance; if (result == UNINITIALIZED) { synchronized (this) { result = instance; if (result == UNINITIALIZED) { result = provider.get(); * in a recursive call. If it returns the same instance, we'll allow it, but if the * instances differ, throw. */ Object currentInstance = instance; if (currentInstance != UNINITIALIZED && currentInstance != result) { throw new IllegalStateException("Scoped provider was invoked recursively returning " + "different results: " + currentInstance + " & " + result + ". This is likely " + "due to a circular dependency."); } instance = result; * can make it eligible for GC. */ provider = null; } } } return (T) result; } public static <T> Provider<T> provider(Provider<T> delegate) { checkNotNull(delegate); if (delegate instanceof DoubleCheck) { * binding, we shouldn't cache the value again. */ return delegate; } return new DoubleCheck<T>(delegate); } public static <T> Lazy<T> lazy(Provider<T> provider) { if (provider instanceof Lazy) { @SuppressWarnings("unchecked") final Lazy<T> lazy = (Lazy<T>) provider; return lazy; } return new DoubleCheck<T>(checkNotNull(provider)); } }
|
DoubleCheck是Provider的具体体现类, 在provider方法中, 返回了DoubleCheck实例, DoubleCheck的精华主要是在get方法中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| SuppressWarnings("unchecked") @Override public T get() { Object result = instance; if (result == UNINITIALIZED) { synchronized (this) { result = instance; if (result == UNINITIALIZED) { result = provider.get(); * in a recursive call. If it returns the same instance, we'll allow it, but if the * instances differ, throw. */ Object currentInstance = instance; if (currentInstance != UNINITIALIZED && currentInstance != result) { throw new IllegalStateException("Scoped provider was invoked recursively returning " + "different results: " + currentInstance + " & " + result + ". This is likely " + "due to a circular dependency."); } instance = result; * can make it eligible for GC. */ provider = null; } } } return (T) result; }
|
get()方法中的代码有没有很熟悉?? 咋一看, 我还以为是DCL单例模式, 其实不然, 它是利用DCL的思想, 将依赖对象缓存到DoubleCheck中, 下次提供依赖时, 直接从缓存拿. 说了这么多, 你可能会问: 究竟Singleton怎么实现单例啊? 其实这个问题在get()方法中已经体现出来了
既然后一次提供依赖时会从缓存拿, 那我们只要保证DoubleCheck之会被初始化一次, 那么每次用到这个依赖时, 都是从缓存拿的, 也就变相的实现了单例, 为了保证DoubleCheck只会被初始化一次, 我们可以在Appication中实现注入, 那就保证整个应用中DoubleCheck只会被初始化一次.
细心的你可能会注意到, 有被Singleton标注的依赖都会在Component实例中被DoubleCheck包装, 而没有的依赖则会直接被工厂类创建出来. 那么我们可以自定义一个注解PerActivity, 那么它就可以管理依赖对象在需要注入依赖的Activity实现局部单例
看完Dagger2这个实现单例的思想瞬间膜拜.
总体来说, Scope注解还是很有用的, 利用它我们可以有效的管理依赖对象的生命周期, 让我们不用再去写一堆的单例类
最后
本篇主要讲了Dagger注入依赖的原理, 重点讲了Scope实现单例的原理, 对于Component和SubComponent我想留到下一篇讲, 下篇我会针对Component和SubComponent来分析, 并利用他们有效的组织依赖注入. 今天就到这里啦…