上一篇记录了如何使用Dagger,其中还漏了一些内容,回头再补。今天来看看Dagger在预编译时期生成的辅助代码,看看Dagger做依赖注入的实现原理是咋样的。
还是从上一篇中最简单的Sample开始。先看下代码:
MainActivity:
public class MainActivity extends AppCompatActivity {
@Inject
UserModel user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerUserComponent.builder()
.userModule(new UserModule())
.build()
.inject(this);
((TextView) findViewById(R.id.text_view)).setText("Name:" + user.getName() + "::Age:" + user.getAge());
}
}
UserModel:
public class UserModel {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
UserModule:
@Module
public class UserModule {
UserModule() {}
@Provides
UserModel provideUsers() {
UserModel user = new UserModel();
user.setName("lala");
user.setAge(18);
return user;
}
}
UserComponent:
@Component(modules = {UserModule.class})
public interface UserComponent {
void inject(MainActivity mainActivity);
}
运行结果如下:
OK,咱们先来看看Dagger为我们上面的代码生成了哪些东东。
咱们自己的类:
1.MainActivity
2.UserComponent
3.UserModel
4.UserModule
Dagger生成的类:
1.DaggerUserComponent
2.UserModule_ProvideUsersFactory
3.MainActivity_MembersInjector
好,下面来逐个看看这几个生成类
直接从我们执行注入的代码下手:
DaggerUserComponent.builder()
.userModule(new UserModule())
.build()
.inject(this);
可以看到,我们通过Builder方式,传一个UserModule的实例,build一个DaggerUserComponent的实例出来,然后调用 inject 方法执行注入操作。
下面喽一眼DaggerUserComponent的代码。
DaggerUserComponent:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerUserComponent implements UserComponent {
private Provider provideUsersProvider;
private MembersInjector mainActivityMembersInjector;
private DaggerUserComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static UserComponent create() {
return builder().build();
}
private void initialize(final Builder builder) {
this.provideUsersProvider = UserModule_ProvideUsersFactory.create(builder.userModule);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideUsersProvider);
}
@Override
public void inject(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
public static final class Builder {
private UserModule userModule;
private Builder() {
}
public UserComponent build() {
if (userModule == null) {
this.userModule = new UserModule();
}
return new DaggerUserComponent(this);
}
public Builder userModule(UserModule userModule) {
if (userModule == null) {
throw new NullPointerException("userModule");
}
this.userModule = userModule;
return this;
}
}
}
这个类非常简单,它实现了咱们写的UserComponent接口,实现了inject方法。重点在初始化 (initialize) 和注入 (inject) 两个方法。
private Provider provideUsersProvider;
private MembersInjector mainActivityMembersInjector;
private void initialize(final Builder builder) {
this.provideUsersProvider = UserModule_ProvideUsersFactory.create(builder.userModule);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideUsersProvider);
}
可以看到,initialize这个方法创建了两个成员变量,provideUsersProvider
和 mainActivityMembersInjector
。
创建Provider的代码引出了第二个生成类: UserModule_ProvideUserFactory
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class UserModule_ProvideUsersFactory implements Factory {
private final UserModule module;
public UserModule_ProvideUsersFactory(UserModule module) {
assert module != null;
this.module = module;
}
@Override
public UserModel get() {
UserModel provided = module.provideUsers();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
}
return provided;
}
public static Factory create(UserModule module) {
return new UserModule_ProvideUsersFactory(module);
}
}
顾名思义,UserModule_ProvideUsersFactory 是一个工厂类,此类用来生产我们用 @Inject 注解的UserModel实例。
上面这句是屁话,UserModel的真正的实例并不在这里生产,可以看到,这个“伪工厂”接受一个咱们写的UserModule的实例,然后在get方法中调用UserModule的provideUsers()方法(咱们自己写的),把拿到的UserModel实例返回。
咱们回到DaggerUserComponent,再瞄一眼初始化的第一句代码:
this.provideUsersProvider = UserModule_ProvideUsersFactory.create(builder.userModule);
在这里创建了一个生产UserModel实例的工厂实例。该实例的get方法返回一个UserModel的实例(从Module的provide方法中拿到的)。
OK,拿到了Provider的实例,来看看初始化的第二行代码:
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideUsersProvider);
这里引出了第三个生成类,MainActivity_MembersInjector.
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector {
private final MembersInjector supertypeInjector;
private final Provider userProvider;
public MainActivity_MembersInjector(MembersInjector supertypeInjector, Provider userProvider) {
assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert userProvider != null;
this.userProvider = userProvider;
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.user = userProvider.get();
}
public static MembersInjector create(MembersInjector supertypeInjector, Provider userProvider) {
return new MainActivity_MembersInjector(supertypeInjector, userProvider);
}
}
MainActivity_MembersInjector的create方法接收两个参数,生成一个实例返回。这个类实现了MembersInjector接口,实现了injectMembers方法,咦?
instance.user = userProvider.get();
真相只有一个,这一句才是真正执行注入的代码。从接收到的Provider实例中通过调用get方法拿到UserModel实例,并赋给传进来的MainActivity实例的user成员变量。这也是为什么我们用 @Inject 注解的变量不可以是private的原因。
所以这么看下来,注入过程还是很简单的,像很多文章说的那样,There is no magic with Dagger.
就在飘飘然的时候,瞄见了这句代码
supertypeInjector.injectMembers(instance);
supertypeInjector?这个是初始化的时候创建塞进来的:
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideUsersProvider);
注意这里有两个长得很像的类,MembersInjector 和 MembersInjectors,卧槽。
MembersInjector是一个接口,就是上面提到的那个,里面只有一个injectMembers抽象方法。那MembersInjectors是什么鬼...
public final class MembersInjectors {
/**
* Returns a {@link MembersInjector} implementation that injects no members
*
* Note that there is no verification that the type being injected does not have {@link Inject}
* members, so care should be taken to ensure appropriate use.
*/
@SuppressWarnings("unchecked")
public static MembersInjector noOp() {
return (MembersInjector) NoOpMembersInjector.INSTANCE;
}
private static enum NoOpMembersInjector implements MembersInjector
初始化中调用的noOp方法返回一个NoOpMembersInjector枚举类,这个类同样实现了MembersInjector接口,在injectMembers方法中check了instance是否为null。
什么鬼,在注入前不是已经check过了么:
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.user = userProvider.get();
}
这个鬼地方先按下不表,因为我也布吉岛,回头再看看回来补上,现在看不懂为什么要连着check两次。
除了上面这个问题,对于Dagger依赖注入的流程应该是比较清晰的。首先build一个DaggerUserComponent实例,把Module传进去,再调它的inject方法,DaggerUserComponent的inject方法会调到MainActivityMembersInjector的injectMembers方法,在这里执行真正的注入。
以上是依赖注入一个实例时Dagger生成的辅助代码。如果我们给两个成员注入,如下:
public class MainActivity extends AppCompatActivity {
@Inject
UserModel user1;
@Inject
UserModel user2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerUserComponent.builder()
.userModule(new UserModule())
.build()
.inject(this);
user2.setName("Arya Stark");
user2.setAge(12);
((TextView) findViewById(R.id.text_view_1)).setText("Name:" + user1.getName() + "::Age:" + user1.getAge());
((TextView) findViewById(R.id.text_view_2)).setText("Name:" + user2.getName() + "::Age:" + user2.getAge());
}
}
就不传图了,结果是两个不一样的TextView内容,因为这是两个不同的实例。
那么问题来了,那单例呢?
还是用这个Sample,我给Component类和provide方法都加上 @Singleton 注解,最后的得到的结果就是单例,怎么做到的?
对比了代码后,我发现加Singleton注解和不加两种情况下,DaggerUserComponent的初始化代码偷偷发生了变化。
不加 @Singleton 注解:
private void initialize(final Builder builder) {
this.provideUsersProvider = UserModule_ProvideUsersFactory.create(builder.userModule);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideUsersProvider);
}
加 @Singleton注解:
private void initialize(final Builder builder) {
this.provideUsersProvider = ScopedProvider.create(UserModule_ProvideUsersFactory.create(builder.userModule));
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideUsersProvider);
}
看出区别了吧?不加注解的时候拿到的Provider是UserModule_ProvideUsersFactory的实例,加了注解后拿到的是ScopedProvider的实例。
好,来看看这个ScopedProvider.
/**
* A {@link Provider} implementation that memoizes the result of a {@link Factory} instance.
*
* @author Gregory Kick
* @since 2.0
*/
public final class ScopedProvider implements Provider {
private static final Object UNINITIALIZED = new Object();
private final Factory factory;
private volatile Object instance = UNINITIALIZED;
private ScopedProvider(Factory factory) {
assert factory != null;
this.factory = factory;
}
@SuppressWarnings("unchecked") // cast only happens when result comes from the factory
@Override
public T get() {
// double-check idiom from EJ2: Item 71
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
instance = result = factory.get();
}
}
}
return (T) result;
}
/** Returns a new scoped provider for the given factory. */
public static Provider create(Factory factory) {
if (factory == null) {
throw new NullPointerException();
}
return new ScopedProvider(factory);
}
}
其实所谓的ScopedProvider就是把Factory包了一层,在里面存储了Factory的实例。当我们调用inject时,DaggerUserComponent会把调用转发给Provider,此时也就是ScopedProvider的get方法,单例的关键就在这里。
这个类里定义了一个静态常量UNINITIALIZED,第一次进入get方法时,会把现在还是静态常量的instance赋给result局部变量。然后进入判断,拿锁,从factory实例中取出UserModel实例,赋给instance和result,然后把result返回。此时,instance变量已经变成了我们之前拿到的那个UserModel实例了。后面再进来,局部变量result(之前的UserModel实例)和静态常量不等,就再也进不去判断,直接返回instance,也就实现了单例。
但是注意,这个单例是存在于DaggerUserComponent的实例中的,也就是说,如果DaggerUserComponent产生了新的实例,那么也会产生新的UserModel实例。不能光说不练,来做个实验。
对MainActivity做以下更改:
public class MainActivity extends AppCompatActivity {
@Inject
UserModel user1;
@Inject
UserModel user2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerUserComponent.builder()
.userModule(new UserModule())
.build()
.inject(this);
user2.setName("Arya Stark");
user2.setAge(12);
((TextView) findViewById(R.id.text_view_1)).setText("Name:" + user1.getName() + "::Age:" + user1.getAge());
((TextView) findViewById(R.id.text_view_2)).setText("Name:" + user2.getName() + "::Age:" + user2.getAge());
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
DaggerUserComponent.builder()
.userModule(new UserModule())
.build()
.inject(MainActivity.this);
((TextView) findViewById(R.id.text_view_1)).setText("Name:" + user1.getName() + "::Age:" + user1.getAge());
((TextView) findViewById(R.id.text_view_2)).setText("Name:" + user2.getName() + "::Age:" + user2.getAge());
}
}, 2000);
}
}
在第一次设置TextView的文字完了两秒后,重新进行一次注入,再更新TextView的显示。现象就是,先显示Arya Stark的信息,两秒后更新为十八岁的lala。因为第二次注入时生成了DaggerUserComponent的新实例,单例也就失效了。
自定义 @UserScope 注解
既然前面已经把Dagger中的 @Singleton 的实现扒了个精光,那么应该很容易自定义Scope了。因为单例存在于ScopedProvider,而ScopedProvider是在Component中创建的,所以要自定义Scope,其实就是控制好Dagger给咱们生成的Component实现的生命周期。
哦对了,先想想Scope是干啥的。我的理解是,保证某个类在一个时期中的实例的单一,也就是在定义的时期中是单例。比如我希望我们的CP项目Model在项目Activity中是单例,那么就可以定义一个ActivityScope,我希望我们的UserModel在用户登陆后直到登出前是一个单例,那么就定义一个从登陆到登出的UserScope。
现在拓展一下我们的Sample. 在MainActivity之外,再创建SecondActivity和ThirdActivity,假设咱们的用户在SecondActivity登录,我们需要UserModel在SecondActivity到ThirdActivity之间是单例。
OK,既然UserScope跨Activity,那只能在比Activity更大的Scope下定义了,这个Scope只能是整个App的ApplicationScope。
好吧,咱们还是按流程来。先为整个App定义最大的Component:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
UserComponent plus(UserModule userModule);
}
注解里标识的AppModule:
@Module
public class AppModule {
private Application application;
public AppModule(Application application) {
this.application = application;
}
@Provides
public Application provideApplication() {
return application;
}
}
然后添加两个Activity,SecondActivity和ThirdActivity,并为他们分别添加Component和Module,代码就不贴了。
这里咱们要用到一个叫做@Subcomponent的注解,它标识子Component在父Component下进行实现,后面看了源码就明白了,先记着。
@Subcomponent(modules = {SecondActivityModule.class})
public interface SecondActivityComponent {
SecondActivity inject(SecondActivity secondActivity);
}
@Subcomponent(modules = {ThirdActivityModule.class})
public interface ThirdActivityComponent {
ThirdActivity inject(ThirdActivity thirdActivity);
}
这两个子Component的接口在inject方法中接收一个自己的Activity,然后返回去。
之后,添加一个Application的子类:
public class DaggerDemoApplication extends Application {
private AppComponent appComponent;
private UserComponent userComponent;
public static DaggerDemoApplication get(Context context) {
return (DaggerDemoApplication) context.getApplicationContext();
}
@Override
public void onCreate() {
super.onCreate();
initAppComponent();
}
private void initAppComponent() {
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
public UserComponent createUserComponent() {
userComponent = appComponent.plus(new UserModule());
return userComponent;
}
public void destroyUserComponent() {
userComponent = null;
}
public AppComponent getAppComponent() {
return appComponent;
}
public UserComponent getUserComponent() {
return userComponent;
}
}
注意,要在Manifest里头为Application标签加上name属性,name设为这个类名。这样,这个类就会在整个App启动的时候率先执行。
就像前面说的,因为UserScope跨Activity,所以要把它存在AppScope里头,也就是说当UserScope开始时创建UserComponent的实现并存起来,当UserScope结束的时候,把UserComponent的实例释放。所以在这里有create和destroy两个方法,用于控制UserComponent的生命周期。
创建UserScope注解:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}
现在更改一下Activity的内容,把MainActivity的内容更换成一个按钮,用于开启SecondActivity,在SecondActivity上添加两个TextView和一个按钮用于开启ThirdActivity,ThirdActivity只有两个TextView。
MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, SecondActivity.class));
}
});
}
}
public class SecondActivity extends AppCompatActivity {
@Inject
UserModel user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
DaggerDemoApplication.get(this).createUserComponent();
DaggerDemoApplication.get(this)
.getUserComponent()
.plus(new SecondActivityModule())
.inject(this);
user.setName("Arya");
user.setAge(12);
((TextView) findViewById(R.id.text_view)).setText("Name:" + user.getName() + ":::Age:" + user.getAge());
findViewById(R.id.button_second).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(SecondActivity.this, ThirdActivity.class));
}
});
}
@Override
public void finish() {
DaggerDemoApplication.get(this).destroyUserComponent();
super.finish();
}
}
public class ThirdActivity extends AppCompatActivity {
@Inject
UserModel user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
DaggerDemoApplication.get(this)
.getUserComponent()
.plus(new ThirdActivityModule())
.inject(this);
((TextView) findViewById(R.id.text_view)).setText("Name:" + user.getName() + ":::Age:" + user.getAge());
}
}
运行一下。
可以看到,我在SecondActivity和ThirdActivity分别进行了一次注入,只在SecondActivity更改了user的值,结果在ThirdActivity中也生效了,说明这个UserModel实例在SecondActivity和ThirdActivity之间是单例的存在。
下面咱来看看Dagger为咱们生成的代码是怎么做到的。
与之前不同,Dagger在这里并没有生成UserComponent实现的单独类,而是将它作为DaggerAppComponent的内部类。
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerAppComponent implements AppComponent {
private DaggerAppComponent(Builder builder) {
assert builder != null;
}
public static Builder builder() {
return new Builder();
}
@Override
public UserComponent plus(UserModule userModule) {
return new UserComponentImpl(userModule);
}
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;
}
}
private final class UserComponentImpl implements UserComponent {
private final UserModule userModule;
private Provider provideUsersProvider;
private UserComponentImpl(UserModule userModule) {
if (userModule == null) {
throw new NullPointerException();
}
this.userModule = userModule;
initialize();
}
private void initialize() {
this.provideUsersProvider = ScopedProvider.create(UserModule_ProvideUsersFactory.create(userModule));
}
@Override
public SecondActivityComponent plus(SecondActivityModule secondActivityModule) {
return new SecondActivityComponentImpl(secondActivityModule);
}
@Override
public ThirdActivityComponent plus(ThirdActivityModule thirdActivityModule) {
return new ThirdActivityComponentImpl(thirdActivityModule);
}
private final class SecondActivityComponentImpl implements SecondActivityComponent {
private final SecondActivityModule secondActivityModule;
private MembersInjector secondActivityMembersInjector;
private SecondActivityComponentImpl(SecondActivityModule secondActivityModule) {
if (secondActivityModule == null) {
throw new NullPointerException();
}
this.secondActivityModule = secondActivityModule;
initialize();
}
private void initialize() {
this.secondActivityMembersInjector = SecondActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), UserComponentImpl.this.provideUsersProvider);
}
@Override
public SecondActivity inject(SecondActivity secondActivity) {
secondActivityMembersInjector.injectMembers(secondActivity);
return secondActivity;
}
}
private final class ThirdActivityComponentImpl implements ThirdActivityComponent {
private final ThirdActivityModule thirdActivityModule;
private MembersInjector thirdActivityMembersInjector;
private ThirdActivityComponentImpl(ThirdActivityModule thirdActivityModule) {
if (thirdActivityModule == null) {
throw new NullPointerException();
}
this.thirdActivityModule = thirdActivityModule;
initialize();
}
private void initialize() {
this.thirdActivityMembersInjector = ThirdActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), UserComponentImpl.this.provideUsersProvider);
}
@Override
public ThirdActivity inject(ThirdActivity thirdActivity) {
thirdActivityMembersInjector.injectMembers(thirdActivity);
return thirdActivity;
}
}
}
}
这个类相对比较长,但是也不难理解。可以看一眼我们是如何在DaggerDemoApplication中创建AppComponent和UserComponent的实现的。
private void initAppComponent() {
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
public UserComponent createUserComponent() {
userComponent = appComponent.plus(new UserModule());
return userComponent;
}
父Component AppComponent实现的创建与之前无异,使用它的Builder,传一个AppModule实例再build。而作为子Component的UserComponent的创建就不同了。这里调用AppComponent的plus方法,这个方法是我们定义的接口,接收一个UserModule实例,返回UserComponent.
在我们调用plus的时候,创建了UserComponentImpl实例并返回。在这个内部类中也有两个我们定义的接口方法,分别接收自己Activity的Module,然后返回自己Activity的Component,在这里又分别创建了SecondActivityComponentImpl和ThirdActivityComponentImpl实例。
再进到这两个内部类中可以看到,真正的注入方法在这里。
@Override
public SecondActivity inject(SecondActivity secondActivity) {
secondActivityMembersInjector.injectMembers(secondActivity);
return secondActivity;
}
注意,这里的secondActivityMembersInjector在SecondActivityComponentImpl的初始化方法中创建:
private void initialize() {
this.secondActivityMembersInjector = SecondActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), UserComponentImpl.this.provideUsersProvider);
}
而provider是在UserComponentImpl中的初始化方法中创建的:
private void initialize() {
this.provideUsersProvider = ScopedProvider.create(UserModule_ProvideUsersFactory.create(userModule));
}
剩下的注入流程和之前的就一样了。inject方法中调用SecondActivity_MembersInjector的injectMembers方法,在这里通过调用Provider的get方法,由provider决定是否需要新建实例,需要时再调到咱们的provide方法拿到真正的实例并返回,不需要时直接返回。
以上是对使用 @SubComponent 注解实现自定义Scope的源码解析。