Android-开源框架和源码分析-06-Dagger2-源码解析

89 阅读3分钟

Dagger2 是 Google 开发的依赖注入框架,基于 Java Annotation ProcessingApt 技术,提供了高效的编译时依赖注入功能。以下是 Dagger2 的源码解析。


Dagger2 核心概念

  1. Component

    • 依赖注入的入口,负责将依赖注入到目标类中。
    • 通过 @Component 注解生成代码。
  2. Module

    • 提供依赖对象的工厂类。
    • 使用 @Module@Provides 注解标记。
  3. Scope

    • 控制依赖对象的生命周期。
    • 使用自定义 @Scope 注解(如 @Singleton)。
  4. Injection Target

    • 目标类,通过 @Inject 标记字段或构造函数,声明需要注入的依赖。
  5. Generated Code

    • 编译期间生成的 Java 代码(如 DaggerXxxComponent)。

工作原理

编译期代码生成

Dagger2 通过注解处理器(@Component, @Module, @Inject 等)在编译期间生成目标代码,避免了运行时反射,提升了性能。

  1. 注解解析

    • @Inject:标记需要注入的字段或构造函数。
    • @Component:解析依赖注入的入口。
    • @Module@Provides:定义如何创建依赖对象。
  2. 代码生成

    • 根据注解生成依赖注入的实现类。

源码解析

1. 注解解析过程

Dagger2 的注解处理器主要实现了 javax.annotation.processing.Processor 接口。

Processor 初始化

java
复制代码
@AutoService(Processor.class)
public final class ComponentProcessor extends BasicAnnotationProcessor {
    @Override
    protected Iterable<? extends ProcessingStep> initSteps() {
        return Arrays.asList(new ComponentProcessingStep(), new ModuleProcessingStep());
    }
}
  • @AutoService:注册 Processor

  • ComponentProcessingStepModuleProcessingStep

    • 解析 @Component@Module 注解。

解析注解

ComponentProcessingStep 负责解析 @Component

java
复制代码
@Override
public Set<? extends Element> process(SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
    for (Element element : elementsByAnnotation.get(Component.class)) {
        ComponentDescriptor descriptor = ComponentDescriptor.create(element);
        generateComponentImplementation(descriptor);
    }
    return ImmutableSet.of();
}
  • ComponentDescriptor

    • @Component 的信息抽象为描述符。
  • generateComponentImplementation

    • 根据描述符生成 DaggerXxxComponent 类。

2. 生成 Component 实现

生成代码示例

java
复制代码
public final class DaggerAppComponent implements AppComponent {
    private final AppModule appModule;

    private DaggerAppComponent(Builder builder) {
        this.appModule = builder.appModule;
    }

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

    public static AppComponent create() {
        return new Builder().build();
    }

    @Override
    public void inject(MainActivity activity) {
        injectMainActivity(activity);
    }

    private MainActivity injectMainActivity(MainActivity instance) {
        instance.someDependency = new SomeDependency();
        return instance;
    }

    public static final class Builder {
        private AppModule appModule;

        public Builder appModule(AppModule appModule) {
            this.appModule = appModule;
            return this;
        }

        public AppComponent build() {
            return new DaggerAppComponent(this);
        }
    }
}
  • DaggerXxxComponent

    • 负责注入依赖对象。
    • 调用 @Provides 方法创建依赖。

3. @Module 和 @Provides

@Module@Provides 定义如何提供依赖对象。

示例

java
复制代码
@Module
public class AppModule {
    @Provides
    SomeDependency provideSomeDependency() {
        return new SomeDependency();
    }
}

代码生成

java
复制代码
@Override
public void generateComponentImplementation(ComponentDescriptor descriptor) {
    ClassName componentName = ClassName.get(descriptor.componentElement());
    MethodSpec providesMethod = MethodSpec.methodBuilder("provideSomeDependency")
            .returns(SomeDependency.class)
            .addStatement("return new SomeDependency()")
            .build();

    TypeSpec generatedClass = TypeSpec.classBuilder("Dagger" + componentName.simpleName())
            .addMethod(providesMethod)
            .build();

    JavaFile.builder(componentName.packageName(), generatedClass)
            .build()
            .writeTo(processingEnv.getFiler());
}

4. @Inject

@Inject 标记的字段或构造函数由 Dagger 生成的代码自动注入。

示例

java
复制代码
public class MainActivity {
    @Inject SomeDependency someDependency;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        DaggerAppComponent.create().inject(this);
    }
}

代码生成

java
复制代码
@Override
public void inject(MainActivity activity) {
    activity.someDependency = new SomeDependency();
}
  • inject() 方法负责将依赖注入到目标类。

5. Scope 生命周期

示例

java
复制代码
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
    void inject(MainActivity activity);
}

代码生成

  • 使用 @Singleton 标记的对象在 DaggerXxxComponent 中缓存,保证全局唯一。
java
复制代码
private final SomeDependency someDependency = new SomeDependency();

@Override
public void inject(MainActivity activity) {
    activity.someDependency = someDependency;
}

Dagger2 优化与特性

  1. 编译时检查

    • 在编译期发现依赖注入问题,避免运行时错误。
  2. 无反射

    • 通过代码生成避免运行时反射,提高性能。
  3. Scope 管理

    • 精确控制对象生命周期。
  4. 多模块支持

    • 支持复杂项目中的模块化依赖注入。

Dagger2 优缺点

优点

  1. 编译时依赖检查,性能优异。
  2. 支持多种依赖模式(构造函数注入、字段注入等)。
  3. 自动生成代码,减少手动工作。

缺点

  1. 学习曲线较高。
  2. 编译期生成代码可能增加构建时间。
  3. 对于小型项目可能显得过于复杂。

总结

Dagger2 是一款强大且高效的依赖注入框架,其核心基于注解处理器和编译期代码生成。通过对 @Component@Module@Inject 的源码解析,可以清晰了解其依赖解析和注入过程。它适用于大型项目,尤其是需要严格依赖管理和性能要求的场景。