看源码学dagger2
为什么要学习dagger2
在项目中,我们经常要使用到各种各样的工具和业务模块。好的项目会采用模块化编程,把业务模块做成一个个组件,通过适配器实现接口和app相连接。这样降低了耦合,在多人协作项目中避免各人项目互相依赖,提高了开发效率,更加便于维护。但是在项目中,仍然避免不了实例化接口的时候造成耦合。dagger2就是为了解决这个问题而出现的。它通过对象工厂实例化对象,然后依赖注入到目标类中,不需要再通过在目标类中用new创建对象。这样在以后如果对象有变化的时候,只要修改对象工厂相关的类就可以,不必在目标类中进行修改。下面我们来学习一下如何使用dagger2。
dagger2中的角色介绍
dagger2主要有2个角色,一个是Component,一个是Module。
Component是连接目标类和它所依赖对象的桥梁。一方面它通过依赖Module获取对象,一方面它定义了那些类可以作为目标类接收这些对象的注入。
Component的代码如下
@Component(modules = MainModule.class)
public interface MainComponent {
PetDelegate petDelegate();
void inject(MainActivity mainActivity);
代码中的Component叫MainComponent,注解@Component表示这是一个Component。modules =表示MainComponent依赖的moudle 是MainModule.class,moudle可以是多个。
Module的作用是提供对象。
Module的代码如下
@Module
public class MainModule {
@Provides
PetDelegate providePetDelegate(){
return new DogAdapter();
}
}
@Module表示MainModule一个Module,@Provides表示这是一个提供对象的方法。这两段代码结合起来作用就是MainComponent从moudule中获得了PetDelegate对象的实例,并把它注入到MainActivity的中PetDelegate属性中。
注:PetDelegate是一个接口,DogAdapter实现了它。
下面我们看看dagger是如何创建一个对象并把它注入到目标类中的
dagger2的基本用法
dagger创建对象有2种方法。分别是通过对象的构造函数创建和通过moudle创建。通过moudle创建的方式上面已经介绍过了,下面介绍下通过对象构造方法创建。
public class User1 implements Serializable {
private String name;
private String pwd;
@Inject
public User1() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
在User1类的构造方法中加上注解 @Inject表示从类的构造方法中获取。
对象创建已经准备就绪了,下面我们build一下工程,让dagger的代码生成器生成代码(对通过注解生成代码感兴趣的童鞋可以了解下AbstractProcessor方面内容),build完成后,我们把它注入到目标类中。注入代码如下
public class MainActivity extends AppCompatActivity {
@Inject
protected PetDelegate petDelegate1;
@Inject
protected User1 u;
private ActivityMainBinding mDataBinding;
private AlertDialog.Builder mBulider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
mDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mDataBinding.setVariable(BR.event, new EventHandler());
}
.....
我们看到MainActivity的两个属性上面也有 @Inject注解,不要把它们和之前构造方法上面的@Inject搞混了。属性上面的@Inject注解表示这个属性用来接收注入的实例,而构造方法上面的@Inject表示通过这个方法提供对象实例。还有一点要注意,属性不能是private,至于为什么这样,下面看了源码大家就知道了。让我们点开DaggerMainComponent(dagger2生成的类),看看它搞的是哪一出吧。
DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);看这段代码就知道 DaggerMainComponent采用了构建者设计模式,它里面有一个内部类负责构建它需要的属性,那我们先从 Builder 来看吧。
public static final class Builder {
private MainModule mainModule;
private Builder() {}
public MainComponent build() {
if (mainModule == null) {
this.mainModule = new MainModule();
}
return new DaggerMainComponent(this);
}
public Builder mainModule(MainModule mainModule) {
this.mainModule = Preconditions.checkNotNull(mainModule);
return this;
}
}
从上面的代码可以看出Builder保存了MainComponent依赖的Module,并把自己传入了MainComponent的构造方法。
private Provider<PetDelegate> providePetDelegateProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
MainComponent构造方法只有一个方法initialize(builder);进去看看
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.providePetDelegateProvider =
MainModule_ProvidePetDelegateFactory.create(builder.mainModule);
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
}
initialize的作用是给MainComponent的providePetDelegateProvider和mainActivityMembersInjector属性赋值。MainModule_ProvidePetDelegateFactory和MainActivity_MembersInjector看上去是二个对象工厂,进去看看。
MainModule_ProvidePetDelegateFactory的代码
private Provider<PetDelegate> providePetDelegateProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
MainComponent构造方法只有一个方法initialize(builder);进去看看
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.providePetDelegateProvider =
MainModule_ProvidePetDelegateFactory.create(builder.mainModule);
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
}
这段代码中MainComponent的属性providePetDelegateProvider和mainActivityMembersInjector被赋值。
我们看看MainModule_ProvidePetDelegateFactory和 MainActivity_MembersInjector这两个工厂类里面做了什么。
MainModule_ProvidePetDelegateFactory的代码如下
public final class MainModule_ProvidePetDelegateFactory implements Factory<PetDelegate> {
private final MainModule module;
public MainModule_ProvidePetDelegateFactory(MainModule module) {
assert module != null;
this.module = module;
}
@Override
public PetDelegate get() {
return Preconditions.checkNotNull(
module.providePetDelegate(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<PetDelegate> create(MainModule module) {
return new MainModule_ProvidePetDelegateFactory(module);
}
/** Proxies {@link MainModule#providePetDelegate()}. */
public static PetDelegate proxyProvidePetDelegate(MainModule instance) {
return instance.providePetDelegate();
}
}
MainModule_ProvidePetDelegateFactory实现了Factory接口。
public interface Factory<T> extends Provider<T> {
}
public interface Provider<T> {
T get();
}
Factory接口继承了Provider接口,Provider接口有一个方法get。我们看在MainModule_ProvidePetDelegateFactoryget方法的实现,它里面调用了 module.providePetDelegate(),看到这里我们就明白了,对象是在这里实例化的。
providePetDelegateProvider获取到值后,传给MainActivity_MembersInjector的create方法,同时还有一个User1_Factory.create()。
User1_Factory的代码如下
public final class User1_Factory implements Factory<User1> {
private static final User1_Factory INSTANCE = new User1_Factory();
@Override
public User1 get() {
return new User1();
}
public static Factory<User1> create() {
return INSTANCE;
}
}
User1_Factory用饿汉式单例获取工厂对象,它的get方法创建User1对象。原来用@Inject构造方法实例化对象是这样实现的。
这样MainActivity的两个属性的对象创建工具都获取到了。MainActivity_MembersInjector做什么我们大致也可以猜到了。下面看看它的代码
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<PetDelegate> petDelegate1Provider;
private final Provider<User1> uProvider;
public MainActivity_MembersInjector(
Provider<PetDelegate> petDelegate1Provider, Provider<User1> uProvider) {
assert petDelegate1Provider != null;
this.petDelegate1Provider = petDelegate1Provider;
assert uProvider != null;
this.uProvider = uProvider;
}
public static MembersInjector<MainActivity> create(
Provider<PetDelegate> petDelegate1Provider, Provider<User1> uProvider) {
return new MainActivity_MembersInjector(petDelegate1Provider, uProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.petDelegate1 = petDelegate1Provider.get();
instance.u = uProvider.get();
}
....
}
create方法在实例化MembersInjector的同时把对象构造器赋值给它的二个成员变量,在方法injectMembers中,对象构造器把对象赋值给了MainActivity。下面我们找到injectMembers在哪调用的。这个流程就走完了。
回到DaggerMainComponent
@Override
public void inject(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
}
DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
在这里调用了inject。
到此dagger基本用法就分析完了。
dagger2的进阶用法
1.单例模式
dagger2通过作用域控制对象是否单例。dagger2中有一个默认的@Singleton注解表示单例。单例注解也可以自定义,它的定义方式如下
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PreActivity {
}
加上@Scope表示这是约束单例作用域的注解,下面简称为Scope注解
Scope注解的用法
1.在Component中加入
@PreActivity
@Component(modules = MainModule.class)
public interface MainComponent {
PetDelegate petDelegate();
void inject(MainActivity mainActivity);
}
2.在module中需要单例的provide方法前面加入
@Module
public class MainModule {
@PreActivity
@Provides
PetDelegate providePetDelegate(){
return new DogAdapter();
}
}
注:如果provide前面加入Scope注解而Component没有加入,则会出错,不能通过编译,反之虽然不会报错,但也没有效果。必须两边都加入才能起作用。
我们看看加了Scope注解后代码中的变化以及它的实现原理吧。
由于对象实例都是由对象创建工具提供的,我们直接来到DaggerMainComponent的initialize方法中,发现果然和之前不一样了
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.providePetDelegateProvider =
DoubleCheck.provider(MainModule_ProvidePetDelegateFactory.create(builder.mainModule));
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
}
之前没加Scope注解代码是这样的
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.providePetDelegateProvider =
MainModule_ProvidePetDelegateFactory.create(builder.mainModule);
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
}
对比一下,多出来一个DoubleCheck.provider,这个DoubleCheck是什么呢?
打开DoubleCheck,它的代码是这样的:
public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
private static final Object UNINITIALIZED = new Object();
private volatile Provider<T> provider;
private volatile Object instance = UNINITIALIZED;
private DoubleCheck(Provider<T> provider) {
assert provider != null;
this.provider = provider;
}
@SuppressWarnings("unchecked") // cast only happens when result comes from the provider
@Override
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
result = provider.get();
Object currentInstance = instance;
if (currentInstance != UNINITIALIZED && currentInstance != result) {
throw new IllegalStateException("Scoped provider was invoked recursively returning "
+ "different results: " + currentInstance + " & " + result);
}
instance = result;
provider = null;
}
}
}
return (T) result;
}
public static <T> Provider<T> provider(Provider<T> delegate) {
checkNotNull(delegate);
if (delegate instanceof DoubleCheck) {
return delegate;
}
return new DoubleCheck<T>(delegate);
}
}
DoubleCheck实现了Provider和Lazy接口,它可以作为Provider和Lazy对象。Lazy的作用下面会写,这里略过。
先看provider方法, MainActivity_MembersInjector实现了Factory接口,而Factory接口继承了Provider,在这里MainActivity_MembersInjector作为Provider而不是DoubleCheck类型,所以返回了
new DoubleCheck(delegate)。而DoubleCheck实现了Provider接口,所以它作为Provider类型可以赋值给providePetDelegateProvider,此时providePetDelegateProvider是一个DoubleCheck对象。
我们再看看DoubleCheck的get方法,很明显,它是一个单例模式,无论调用多少次,只会产生一个provider.get()对象。
provider.get()是什么呢,看看下面代码
public final class MainModule_ProvidePetDelegateFactory implements Factory<PetDelegate> {
....
@Override
public PetDelegate get() {
return Preconditions.checkNotNull(
module.providePetDelegate(), "Cannot return null from a non-@Nullable @Provides method");
}
.....
}
上面也就是不使用Scope注解的providePetDelegateProvider的get方法,每get一次会new一个新对象,如果目标类有多个同类型的属性,使用Scope注解这些属性指向同一个地址,不使用则是每次get都new一下,指向不同的地址。
2.懒加载
懒加载就是在对象使用的时候再进行初始化
写法:
属性的写法
@Inject
protected Lazy<PetDelegate> petDelegate1;
调用对象的写法
petDelegate1.get().feedPet()
下面我们看下源码,懒加载是如何实现的
先去看看对象创建工具
private void initialize(final Builder builder) {
this.providePetDelegateProvider =
DoubleCheck.provider(MainModule_ProvidePetDelegateFactory.create(builder.mainModule));
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
}
啊喔,和没加lazy的没有区别,再去看注入的代码
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.petDelegate1 = DoubleCheck.lazy(petDelegate1Provider);
instance.u = uProvider.get();
}
这里发现生成对象的时候不是petDelegate1Provider.get()了,而是DoubleCheck.lazy(petDelegate1Provider),进去看看
/** Returns a {@link Lazy} that caches the value from the given provider. */
public static <T> Lazy<T> lazy(Provider<T> provider) {
if (provider instanceof Lazy) {
return lazy;
}
return new DoubleCheck<T>(checkNotNull(provider));
}
原来返回的是DoubleCheck类型,难怪调用get才能获取真正的对象实例了。这里还有一点要说下,如果前面使用了Scope注解,那么传入的provider对象之前经过了DoubleCheck.provider的包装,成为了DoubleCheck对象,DoubleCheck对象实现了Lazy接口,于是返回的都是相同的对象,这里可以看出谷歌设计的精妙了。
3.Component依赖
Component写法
@UserScope
@Component(dependencies = MainComponent.class)
public interface TestdependComponent {
void inject(DependComActivity dependComActivity);
}
注入时写法
DaggerTestdependComponent.builder().mainComponent(DaggerMainComponent.create()).build().inject(this);
看到代码我们可以发现DaggerTestdependComponent的内部bulid类保存了DaggerMainComponent的实例。它是在哪用的呢?看下DaggerTestdependComponent的源码
private void initialize(final Builder builder) {
this.petDelegateProvider =
new Factory<PetDelegate>() {
private final MainComponent mainComponent = builder.mainComponent;
@Override
public PetDelegate get() {
return Preconditions.checkNotNull(
mainComponent.petDelegate(),
"Cannot return null from a non-@Nullable component method");
}
};
....
}
原来petDelegateProvider创建了一个对象生成器,它的get方法通过调用mainComponent.petDelegate()来生成对象。这里的mainComponent就是DaggerMainComponent,因为DaggerMainComponent实现了MainComponent接口。点开DaggerMainComponent,看下mainComponent.petDelegate()干了什么。
@Override
public PetDelegate petDelegate() {
return providePetDelegateProvider.get();
}
这就回到了DaggerMainComponent之前分析过的部分了,真相大白。
4.@Subcomponent
Subcomponent我个人理解是Component依赖的另外一种写法。
父Component写法
@PreActivity
@Component(modules = MainModule.class)
public interface MainComponent {
TestSubComponent testSubComponent();
PetDelegate petDelegate();
void inject(MainActivity mainActivity);
}
子Component写法
@UserScope
@Subcomponent(modules = UserModule.class)
public interface TestSubComponent {
void inject(SubComActivity activity);
}
注入写法
DaggerMainComponent.create().testSubComponent().inject(this);
我们打开源码看看它和组件依赖的区别在哪
private final class TestSubComponentImpl implements TestSubComponent {
private final UserModule userModule;
private Provider<User> provideUserProvider;
private MembersInjector<SubComActivity> subComActivityMembersInjector;
private TestSubComponentImpl() {
this.userModule = new UserModule();
initialize();
}
@SuppressWarnings("unchecked")
private void initialize() {
this.provideUserProvider =
DoubleCheck.provider(UserModule_ProvideUserFactory.create(userModule));
this.subComActivityMembersInjector =
SubComActivity_MembersInjector.create(
DaggerMainComponent.this.providePetDelegateProvider,
provideUserProvider,
User1_Factory.create());
}
@Override
public void inject(SubComActivity activity) {
subComActivityMembersInjector.injectMembers(activity);
}
}
原来Subcomponent在父component中是个内部类,值得注意的是, DaggerMainComponent.this.providePetDelegateProvider用的是父类的对象生成器,所以是否为单例依然由父类的Scope注解控制
到这里,dagger2的用法大致分析完了,不知道你懂没懂,反正我懂了。(^-^)。
最后还有一点,上面所有注入例子都没有传入module对象,是因为Component的Builder类中会在Component依赖的module对象没有传入的时候自动创建一个。但如果module对象带有参数,则要手动在注入时传入,否则会出现问题。
public MainComponent build() {
if (mainModule == null) {
this.mainModule = new MainModule();
}
return new DaggerMainComponent(this);
}
本人水平有限,如果有错漏的地方请不吝指点。本文为原创,欢迎转载,请转载时注明作者。