您的位置:首页 > 移动开发 > Android开发

Dagger2源码剖析

2016-07-28 15:59 405 查看

Dagger2源码剖析

Dagger是一个非常优秀的IOC框架,使用Dagger能够极大减少代码耦合,介绍Dagger如何使用的文章网上有很多,在这里给大家推荐3篇,作者讲得非常白话,大家应该可以理解:

Android:dagger2让你爱不释手-基础依赖注入框架篇

Android:dagger2让你爱不释手-重点概念讲解、融合篇

Android:dagger2让你爱不释手-终结篇

在使用过Dagger之后,大家不免会对其实现原理产生疑问,本文就对Dagger的源码进行剖析。(由于dagger代码并未开源,一些细节方面的东西可能讲不到)

首先Dagger是基于APT开发的,所以请大家先看下我之前写的一篇文章

编译期注解浅析

好的,终于完成了系列的准备工作,

接下来咱们还是沿着我上篇文章中提到的编译期注解的三要素,一一剖析Dagger框架

注解

dagger里面常用的注解

无非就是

@Inject

@Moudel

@Component

@Qualifier

@Scope

@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Inject {}


@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
@Documented
public @interface Qualifier {}


@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
@Documented
public @interface Scope {}


这3个注解不来自dagger,而来自java本身!,通过这些注解的源码我们关键要捕获一个信息,这些注解在哪里使用,可以看到Inject可以在方法,构造方法,属性上面使用,而Qualifier和Scope则只能在注解上面使用(意味着我们不能直接使用他们,所以就有了@Name @Singleton这些注解)

再看看dagger自己写的注解

@Retention(RUNTIME)
@Target(TYPE)
@Documented
public @interface Component {
Class<?>[] modules() default {};

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


Component注解在类上,可以包含多个Modules,也可以依赖多个Component.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Module {
Class<?>[] includes() default {};
}


Module也是注解在类上

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface Provides {
enum Type {
UNIQUE,
SET,
SET_VALUES;
}

Type type() default Type.UNIQUE;
}


在@Provides这个里面需要注意的是”SET”的这个设置,这个是什么意思呢?如果你选择了”UNIQUE”(其实就是不选)。那么别人一需要这个对象就会来你这里找(必须是唯一的,除了Inject(因为他们优先级不同)),但使用了SET后,你其实就是把生产出来的对象扔到一个对象池里,需要的时候从池里面拿。(这个是个人理解,如果有误,这块请大家私信我,我也好好学习学习)。

处理注解的类

apt 'com.google.dagger:dagger-compiler:{version}'


这也是我们为什么需要在Build.gradle里面加上这句话的原因,因为我们需要他们在编译期生成代码

整个Dagger的流程其实就是一个画图的过程,将能够提供对象的类于需要对象的类画在一张图上,这样就实现了所谓依赖注入

接下来我们看一下处理注解的类:

首先,我们必须找到注解的入口

@AutoService(Processor.class)

public final class ComponentProcessor

extends BasicAnnotationProcessor {}


没错,只是这个类(当然里面有很多方法),包括上面的注解分析,还有这里处理注解的类,如果你找的和我不一样,那说明你是在看dagger1,github上只有1

这个类会生成怎么样的代码呢?

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerAppComponent implements AppComponent {
private Provider<HRApp> provideApplicationProvider;

private DaggerAppComponent(Builder builder) {
assert builder != null;
initialize(builder);
}

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

private void initialize(final Builder builder) {
this.provideApplicationProvider = ScopedProvider.create(AppModule_ProvideApplicationFactory.create(builder.appModule));
}

@Override
public HRApp getApplication() {
return provideApplicationProvider.get();
}

public static final class Builder {
private AppModule appModule;

private Builder() {
}

public AppComponent build() {
if (appModule == null) {
throw new IllegalStateException("appModule must be set");
}
return new DaggerAppComponent(this);
}

public Builder appModule(AppModule appModule) {
if (appModule == null) {
throw new NullPointerException("appModule");
}
this.appModule = appModule;
return this;
}
}
}


@Generated("dagger.internal.codegen.ComponentProcessor")
public final class AppModule_ProvideApplicationFactory implements Factory<HRApp> {
private final AppModule module;

public AppModule_ProvideApplicationFactory(AppModule module) {
assert module != null;
this.module = module;
}

@Override
public HRApp get() {
HRApp provided = module.provideApplication();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
}
return provided;
}

public static Factory<HRApp> create(AppModule module) {
return new AppModule_ProvideApplicationFactory(module);
}
}


这个是component和module生成的代码,module其实就是生成一个产生对象的工厂。每次需要对象的时候,现在看到了吧,为什么我们的component要用接口,因为dagger要实现它。现在情况是module生成的类提供对象,component拿到这个对象然后注入到需要它的对象中,然而怎么知道谁需要呢?

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class BaseActivity_MembersInjector implements MembersInjector<BaseActivity> {
private final MembersInjector<AppCompatActivity> supertypeInjector;
private final Provider<HRApp> applicationProvider;

public BaseActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<HRApp> applicationProvider) {
assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert applicationProvider != null;
this.applicationProvider = applicationProvider;
}

@Override
public void injectMembers(BaseActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.application = applicationProvider.get();
}

public static MembersInjector<BaseActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<HRApp> applicationProvider) {
return new BaseActivity_MembersInjector(supertypeInjector, applicationProvider);
}
}


一个类有@inject注解的时候就会生成这样的一个类,这类就是这个类所以需要注入的汇总。

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerActivityComponent implements ActivityComponent {
private Provider<HRApp> getApplicationProvider;
private MembersInjector<BaseActivity> baseActivityMembersInjector;

private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}

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

private void initialize(final Builder builder) {
this.getApplicationProvider = new Factory<HRApp>() {
private final AppComponent appComponent = builder.appComponent;
@Override public HRApp get() {
HRApp provided = appComponent.getApplication();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable component method");
}
return provided;
}
};
this.baseActivityMembersInjector = BaseActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), getApplicationProvider);
}

@Override
public void inject(BaseActivity baseActivity) {
baseActivityMembersInjector.injectMembers(baseActivity);
}

public static final class Builder {
private ActivityModule activityModule;
private AppComponent appComponent;

private Builder() {
}

public ActivityComponent build() {
if (activityModule == null) {
this.activityModule = new ActivityModule();
}
if (appComponent == null) {
throw new IllegalStateException("appComponent must be set");
}
return new DaggerActivityComponent(this);
}

public Builder activityModule(ActivityModule activityModule) {
if (activityModule == null) {
throw new NullPointerException("activityModule");
}
this.activityModule = activityModule;
return this;
}

public Builder appComponent(AppComponent appComponent) {
if (appComponent == null) {
throw new NullPointerException("appComponent");
}
this.appComponent = appComponent;
return this;
}
}
}


看到了吧!我们经常写的void inject(xxx),这时候就会在对应的component里面生成对应的注入对象,这样component就知道谁需要注入了。

形象的说,含有注解的类生成的类相对于一次汇总将本类所有需求汇总汇报给component生成的类,然后comonent知道需要后就找生产对应对象的工厂要东西了。

调用api

dagger的调用api就是component生成的那个类,一般是先build出,然后调个inject(xxx),如果上面认真看代码的话,就可以看到这个方法将会调那个含注解类生成的类的方法,这个方法就真正实现了注入,而那个对象的提供者,是在component构建含注解类生成的类的时候传入的。

好了,dagger流程基本就是这样,有个关键点没讲,那就是那个源码中是如何生成代码,没办法google没有开源dagger2的源码,我只能找到其中core部分的,其中编译部分找不到,有知道的人欢迎联系我。

后记

个人认为dagger的出现非常大解决了android耦合问题,和mvp配合简直耦合直降,代码结构瞬间清晰。希望大家以后多多使用mvp+dagger的组合写出优秀的代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 dagger android