手写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...

相关推荐
幻雨様1 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端3 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.4 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton5 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw9 小时前
安卓图片性能优化技巧
android
风往哪边走9 小时前
自定义底部筛选弹框
android
Yyyy48210 小时前
MyCAT基础概念
android
Android轮子哥10 小时前
尝试解决 Android 适配最后一公里
android
雨白11 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走12 小时前
自定义仿日历组件弹框
android