手写Dagger2的核心实现和Dagger2的流程解析

在上一篇中,我们介绍了Dagger2的使用方式,这一篇,我们将会就Dagger2的核心原理实现进行解析,同时还会手写Dagger2的基本实现。

我们知道,使用Dagger2的时候,需要用到这两个关键的依赖:

arduino 复制代码
// 导入API支持,包括注解
implementation 'com.google.dagger:dagger:2.28.3'
// 使用Dagger2的注解处理器APT
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'

本篇文章主要是手写核心"com.google.dagger:dagger:2.28.3"。

Dagger2的核心实现

我们在使用Dagger2的时候,需要4个注解,因此我们首先写4个注解。

Component

less 复制代码
@Target(TYPE)
@Retention(RUNTIME)
public @interface Component {

    Class<?>[] modules() default {};
}

Inject

less 复制代码
@Target({CONSTRUCTOR, FIELD})
@Retention(RUNTIME)
public @interface Inject {}

Module

less 复制代码
@Target(TYPE)
@Retention(RUNTIME)
public @interface Module {}

Provides

less 复制代码
@Target(METHOD)
@Retention(RUNTIME)
public @interface Provides {}

另外,我们知道,Dagger2支持单例,这个又是怎么实现的呢?其实是通过一个双重检查锁实现的。

这些逻辑是Javac的过程中生成的。

因此,我们也需要写一个同样的DoubleCheck类:

csharp 复制代码
public final class DoubleCheck<T> implements Provider<T> { // 单例处理的类

    private static final Object UNINITIALIZED = new Object(); // 为了单例的检查而已

    private volatile Provider<T> provider; // 最上层实例化对象的 接口
    private volatile Object instance = UNINITIALIZED;

    private DoubleCheck(Provider<T> provider) {
        this.provider = provider;
    }

    @Override // 单例,对象初始化一次
    public T get() {
        Object result = instance; // instance = new Student();
        if (result == UNINITIALIZED) {
            synchronized (this) {
                result = instance;
                if (result == UNINITIALIZED) {
                    instance = result = provider.get(); // new Student();
                    provider = null;
                }
            }
        }
        return (T) result;
    }

    public static <T> Provider<T> provider(Provider<T> delegate) {
        Preconditions.checkNotNull(delegate); // 工具类,检查
        if (delegate instanceof DoubleCheck) {
            return delegate;
        }
        return new DoubleCheck<T>(delegate);
    }
}

对于Provider,他支持泛型,因为我们传入的对象可以是任意的对象。

csharp 复制代码
public interface Provider<T> {
    T get();
}

另外,注入的标准通过Javac编译之后:

依赖注入的标准MembersInjector,这里的泛型指的是我们要把对象注入到哪里?

csharp 复制代码
// 
依赖注入的标准
public interface MembersInjector<T> { // T == 我们要把对象注入到  MainActivity.this那里  MainActivity110那里
    void injectMembers(T instance);
}

最后,我们还需要一个工具类来做一些安全检查:

typescript 复制代码
public class Preconditions {

    public static <T> T checkNotNull(T value) {
        if (null == value) {
            throw new NullPointerException("value is null exception..");
        }
        return value;
    }

    public static <T> T checkNotNull(T value, String errorMessage) {
        if (null == value) {
            throw  new IllegalArgumentException(errorMessage);
        }
        return value;
    }
}

对于module里边的类,通过Module注解,我们需要在编译期之后,生成需要的类。

我们看一下生成类的内部细节:

从上图来看,我们还需要这样的一个接口来做module内容处理:

csharp 复制代码
public interface Factory<T> extends Provider<T> {
}

到目前为止,我们手写的整体结构如下:

我们已经把Dagger2的基础逻辑写好了,那么应该如何使用呢?

例如,我们创建一个Student类,这是我们希望注入的对象:

csharp 复制代码
public class Student {

    @Inject // 标记 代表此对象Student 是被注入的来源Student   ---> MainActivity目标
    public Student() {

    }

}

首先处理第一个注解Provides,生成相应的Factory的逻辑,需要注意的是,我们应该手动生成对应的Factory,而不是利用Dagger2的逻辑:

typescript 复制代码
// TODO 模拟 这个是编译期 APT 自动生成的  // 第一个注解
public enum Student_Factory  implements Factory<Student> {

    INSTANCE;

    @Override
    public Student get() {
        return new Student();
    }

    public static Factory<Student> create() {
        return INSTANCE;
    }
}

然后处理第二个注解:Module。 新建一个StudentModule,以便用来模拟注入流程:

typescript 复制代码
@Module
public class StudentModule {

    @Provides
    public Student providerStudent() {
        return new Student();
    }
}

Javac之后编译生成的类是这样的:

typescript 复制代码
// TODO 模拟 这个是编译期 APT 自动生成的  // 第二个注解
public class StudentModule_ProviderStudentFactory implements Factory<Student> {

    private StudentModule studentModule; // 包裹

    public StudentModule_ProviderStudentFactory(StudentModule studentModule) {
        this.studentModule = studentModule;
    }

    @Override
    public Student get() {
        return Preconditions.checkNotNull(
                studentModule.providerStudent(), "你个货乱搞 无法studentModule.providerStudent()");
    }

    // 暴露给外界用的
    public static Factory<Student> create(StudentModule module) {
        return new StudentModule_ProviderStudentFactory(module);
    }
}

开始处理第三个注解,Component:

java 复制代码
@Component(modules = StudentModule.class)
public interface StudentComponent { // 快递员

    // 写注入目标  MainActivity的this
    void inject(MainActivity mainActivity);
}

经过Javac之后,会生成下边类似的代码:

typescript 复制代码
// TODO 模拟 这个是编译期 APT 自动生成的  // 第三个注解
public class DaggerStudentComponent implements StudentComponent {

    public DaggerStudentComponent(Builder builder) {
        // 这里面没有代码生成,是靠我们的第四个注解
        initialize(builder);
    }

    // 第四个注解生成的代码
    private Provider<Student> providerDogProvider;
    private MembersInjector<MainActivity> mainActivityMembersInjector;

    private void initialize(final Builder builder) {
        this.providerDogProvider = StudentModule_ProviderStudentFactory.create(builder.studentModule);
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(providerDogProvider);
    }


    public static Builder builder() {
        return new Builder();
    }

    public static final class Builder {

        // 定义我们的包裹  是靠我们的第四个注解
        StudentModule studentModule;

        private Builder() {}

        public StudentComponent build() {
            if (studentModule == null) {
                studentModule = new StudentModule();
            }

            return new DaggerStudentComponent(this);
        }

        /**
         * @deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
         */
        @Deprecated
        public Builder studentModule(StudentModule dogModule) {
            Preconditions.checkNotNull(dogModule);
            return this;
        }
    }

    // 对外提供Builder
    public static StudentComponent create() {
        return builder().build();
    }

    // 第四个注解生成的
    // 往目标(MainActivity)中去注入
    @Override // MainActivity this
    public void inject(MainActivity mainActivity) {
        // 启动 MainActivity_MembersInjector 完成依赖注入
        mainActivityMembersInjector.injectMembers(mainActivity);
    }
}

这里也解释了为什么我们写的Components必须是接口,因为源码中使用的implements.

最后我们来处理第四个注解:Inject

java 复制代码
@Inject // 第四个注解, 这里不能写成private,因为生成的源码中,如果是同一个包,也可以写成 Student student;
public Student student;

**因为一旦写成private,这里就无法拿到对应的引用了。 **

最终,我们来测试一下最终的效果:

scala 复制代码
// 第四步 注入目标
public class MainActivity extends AppCompatActivity {

    @Inject // 第四个注解
    public Student student;

    @Inject // 第四个注解
    public Student student2;

    @Override
    protected void onCreate(Bundle savedInstanceState) { // 方法进栈
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 第三个注解生成的类
        DaggerStudentComponent.create().inject(this);

        Toast.makeText(this, "student:" + student.hashCode(), Toast.LENGTH_SHORT).show();

        Toast.makeText(this, "student:" + student2.hashCode(), Toast.LENGTH_SHORT).show();
    }
}

Dagger2的流程解析

Dagger2的入口,通过一个inject标记一个对象。

java 复制代码
@Inject // 第四个注解
public Student student;

然后会进入这里

kotlin 复制代码
// 第三个注解生成的类
DaggerStudentComponent.create().inject(this);

之后会进入到,DaggerStudentComponent#inject:

typescript 复制代码
@Override // MainActivity this
public void inject(MainActivity mainActivity) {
    // 启动 MainActivity_MembersInjector 完成依赖注入
    mainActivityMembersInjector.injectMembers(mainActivity);
}

然后会进入MainActivity_MembersInjector#injectMembers:

ini 复制代码
@Override  // 注入的方法
public void injectMembers(MainActivity instance) { // instance == MainActivity this
    if (null == instance) {
        throw new NullPointerException("inject target instance is null");
    }
    // MainActivity this student = new Student(); 依赖注入框架
    instance.student = studentProvider.get(); // MainActivity this.student = new Student();
    instance.student2 = studentProvider.get();
}

之后会到这里StudentModule_ProviderStudentFactory#get:

kotlin 复制代码
@Override
public Student get() {
    return Preconditions.checkNotNull(
            studentModule.providerStudent(), "Cannot return null for studentModule.providerStudent()");
}

在这里通过调用studentModule.providerStudent(),最终生成了实例:

typescript 复制代码
@Provides
public Student providerStudent() {
    return new Student();
}

这就是Dagger2整个依赖入住的流程,MainActivity依赖Dagger2对一些对象进行注入。

测试源码链接:github.com/xingchaozha...

相关推荐
zhangphil19 分钟前
Android绘图Path基于LinearGradient线性动画渐变,Kotlin(2)
android·kotlin
watl01 小时前
【Android】unzip aar删除冲突classes再zip
android·linux·运维
键盘上的蚂蚁-1 小时前
PHP爬虫类的并发与多线程处理技巧
android
喜欢猪猪2 小时前
Java技术专家视角解读:SQL优化与批处理在大数据处理中的应用及原理
android·python·adb
JasonYin~3 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果---手机查看电量
android·华为·harmonyos
zhangphil3 小时前
Android adb查看某个进程的总线程数
android·adb
抛空4 小时前
Android14 - SystemServer进程的启动与工作流程分析
android
Gerry_Liang6 小时前
记一次 Android 高内存排查
android·性能优化·内存泄露·mat
天天打码7 小时前
ThinkPHP项目如何关闭runtime下Log日志文件记录
android·java·javascript
爱数学的程序猿10 小时前
Python入门:6.深入解析Python中的序列
android·服务器·python