Dagger2源码剖析
Dagger是一个非常优秀的IOC框架,使用Dagger能够极大减少代码耦合,介绍Dagger如何使用的文章网上有很多,在这里给大家推荐3篇,作者讲得非常白话,大家应该可以理解:
在使用过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的组合写出优秀的代码