Dagger2注入框架原理简要分析
使用Dagger2需要的依赖:
implementation 'com.google.dagger:dagger-android:2.46'
implementation 'com.google.dagger:dagger-android-support:2.46'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.46'
annotationProcessor 'com.google.dagger:dagger-compiler:2.46'
示例代码:
这里先给出我的示例代码,github上的demo点这里👈
- MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Inject
Gson gson;
@Inject
Gson gson2;
@Inject
SwordMan swordMan;
//@Inject
//Car car;
ActivityMainBinding myBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
App.get(MainActivity.this).getActivityComponent().inject(this);
onClick();
if(gson.hashCode() == gson2.hashCode()){
Toast.makeText(this, "Same", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Different", Toast.LENGTH_SHORT).show();
}
myBinding.btTest2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, swordMan.fighting(), Toast.LENGTH_SHORT).show();
}
});
}
private void onClick(){
myBinding.btTest1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
}
});
}
}
- SecondActivity
public class SecondActivity extends AppCompatActivity {
ActivitySecondBinding S_Binding;
@Inject
Lazy<SwordMan> swordManLazy;//实现懒加载
SwordMan swordMan = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
S_Binding = DataBindingUtil.setContentView(this,R.layout.activity_second);
App.get(SecondActivity.this).getActivityComponent().inject(this);
if(swordMan == null){
Toast.makeText(this, "暂未初始化", Toast.LENGTH_SHORT).show();
}
swordMan = swordManLazy.get();
//setContentView(R.layout.activity_second);
S_Binding.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(SecondActivity.this, swordMan.fighting(), Toast.LENGTH_SHORT).show();
}
});
}
}
- App
注意App类需要在manifest清单文件中声明。
public class App extends Application {
ActivityComponent activityComponent;
@Override
public void onCreate() {
super.onCreate();
activityComponent =
DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
.build();
}
public static App get(Context context){
return (App) context.getApplicationContext();
}
ActivityComponent getActivityComponent(){
return activityComponent;
}
}
- Component类
@ApplicationScope
@Component(modules = GsonModule.class,dependencies = SwordmanComponent.class)
public interface ActivityComponent {
void inject(MainActivity activity);
void inject(SecondActivity activity);
}
@Component(modules = SwordmanModule.class)
public interface SwordmanComponent {
SwordMan getSwordman();
}
- Module类以及实体类
@Module
public class GsonModule {
@ApplicationScope
@Provides
public Gson provideGson(){
return new Gson();
}
}
@Module
public class SwordmanModule {
@Provides
public SwordMan provideSwordman(){
return new SwordMan();
}
}
public class SwordMan {
@Inject
public SwordMan(){
}
public String fighting(){
return "欲为大树,莫于草争";
}
}
生成代码分析
Dagger2是通过注解生成中间类的方式帮我们注入依赖的,我们就来分析它生成的中间类的代码。
由于注入器是在App类中初始化的,所以我们先从App类开始看,App类中最重要的无非就是这一句:
activityComponent =
DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
.build();
通过DaggerActivityComonent以及builder的配置生成了一个注入器接口的实现类,所以我们先看DaggerActivityComponent类
DaggerActivityComponent类
public final class DaggerActivityComponent {
private DaggerActivityComponent() {
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private GsonModule gsonModule;
private SwordmanComponent swordmanComponent;
private Builder() {
}
public Builder gsonModule(GsonModule gsonModule) {
this.gsonModule = Preconditions.checkNotNull(gsonModule);
return this;
}
public Builder swordmanComponent(SwordmanComponent swordmanComponent) {
this.swordmanComponent = Preconditions.checkNotNull(swordmanComponent);
return this;
}
public ActivityComponent build() {
if (gsonModule == null) {
this.gsonModule = new GsonModule();
}
Preconditions.checkBuilderRequirement(swordmanComponent, SwordmanComponent.class);
return new ActivityComponentImpl(gsonModule, swordmanComponent);
}
}
private static final class ActivityComponentImpl implements ActivityComponent {
...
}
}
我们先来看前面有关Builder的方法,由于我们在Activity的Component注解中添加了modules和dependencies的值,所以在builder中就会生成响应的gsonModule(GsonModule gsonModule)和swordmanComponent(SwordmanComponent swordmanComponent)方法,这两个方法分别是用来设置生成的注入器中的gsonModule和swordmanComponent对象的。
通过App类中的调用的代码我们可以发现,对于注解中的modules,我们在创建注入器的时候是不需要手动添加的,但是对dependencies注解来说就需要手动添加:
DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
.build();//手动添加了DaggerSwordmanComponent的注入器
builder中的Preconditions.checkNotNull()只是用来判空的,总的来说,builder这个内部类就是用来帮助构建注入器实例的。所以我们接下来就来看这个注入器实例:
private static final class ActivityComponentImpl implements ActivityComponent {
private final SwordmanComponent swordmanComponent;
private final ActivityComponentImpl activityComponentImpl = this;
private Provider<Gson> provideGsonProvider;
private Provider<SwordMan> getSwordmanProvider;
private ActivityComponentImpl(GsonModule gsonModuleParam,
SwordmanComponent swordmanComponentParam) {
this.swordmanComponent = swordmanComponentParam;
initialize(gsonModuleParam, swordmanComponentParam);
}
@SuppressWarnings("unchecked")
private void initialize(final GsonModule gsonModuleParam,
final SwordmanComponent swordmanComponentParam) {
this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam));
this.getSwordmanProvider = new GetSwordmanProvider(swordmanComponentParam);
}
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
@Override
public void inject(SecondActivity activity) {
injectSecondActivity(activity);
}
private MainActivity injectMainActivity(MainActivity instance) {
...
}
private SecondActivity injectSecondActivity(SecondActivity instance) {
...
}
private static final class GetSwordmanProvider implements Provider<SwordMan> {
...
}
}
先不看最后一个内部类,先看注入器类ActivityComponentImpl 实现了 ActivityComponent 接口,也就是说它就是实际的注入器类,这个类的构造方法是私有的,说明只能通过构造器来构造实例。先关注它的构造方法,构造方法传入的参数正是我们在Component接口的注解中写入的值:
@Component(modules = GsonModule.class,dependencies = SwordmanComponent.class)
...
private void initialize(final GsonModule gsonModuleParam,
final SwordmanComponent swordmanComponentParam){
...
}
传入了一个GsonModule和一个SwordmanComponent,和目前这个ActivityComponent类似,这个SwordmanComponent肯定也是有一个实现类的,我们后面再看这两个类的具体内容。
接着我们接续看它的注入依赖的方法,我们在注入依赖时,显然是用到了inject方法,对应不同的注入对象,将会调用不同的inject的重载方法,我们先看MainActivity的注入方法:
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectGson(instance, provideGsonProvider.get());
MainActivity_MembersInjector.injectGson2(instance, provideGsonProvider.get());
MainActivity_MembersInjector.injectSwordMan(instance, Preconditions.checkNotNullFromComponent(swordmanComponent.getSwordman()));
return instance;
}
injectMainActivity中分别调用了注入的方法,很显然,就是将我们在MainActivity中标记为需要注入的变量给注入参数,我们接下来看这个MainActivity_MembersInjector中间类。
MainActivity_MembersInjector
就这个类的命名来说,它应该是具体负责成员变量注入依赖的注入器。前面说到在ActivityComponentImpl调用了它的injectGson等方法,我们来看这三个方法:
@InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.gson")
public static void injectGson(MainActivity instance, Gson gson) {
instance.gson = gson;
}
@InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.gson2")
public static void injectGson2(MainActivity instance, Gson gson2) {
instance.gson2 = gson2;
}
@InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.swordMan")
public static void injectSwordMan(MainActivity instance, SwordMan swordMan) {
instance.swordMan = swordMan;
}
看到这里,这三个方法的作用已经非常明显了,将我们需要注入依赖的对象传入这三个方法中,方法就会给需要注入依赖对象中标记为@Inject的成员变量赋值。至于这个@InjectedFieldSignature注解,@InjectedFieldSignature注解是Dagger中的一个自定义注解,用于帮助Dagger在运行时自动生成代码以实现依赖注入。它用于标记要进行依赖注入的字段,并提供了一个字符串参数,用于标识该字段所依赖的对象的类型。在运行时,Dagger会扫描这些注解并自动生成相应的代码,以实现将依赖注入到被标记的字段中。
何处真正产生了实际参数
这时候新的问题产生了,这些被注入的参数是在哪里被初始化的呢,换句话说,injectGson()方法中的第二个参数gson是在哪里被开辟空间的呢,答案就在之前的ActivityComponentImpl中:
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectGson(instance, provideGsonProvider.get());
...
}
从这里可以看出,这个实际被注入的参数是由provideGsonProvider的get方法提供的:
@SuppressWarnings("unchecked")
private void initialize(final GsonModule gsonModuleParam,
final SwordmanComponent swordmanComponentParam) {
this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam));
this.getSwordmanProvider = new GetSwordmanProvider(swordmanComponentParam);
}
...
public final class GsonModule_ProvideGsonFactory implements Factory<Gson> {
private final GsonModule module;
public GsonModule_ProvideGsonFactory(GsonModule module) {
this.module = module;
}
@Override
public Gson get() {
return provideGson(module);
}
public static GsonModule_ProvideGsonFactory create(GsonModule module) {
return new GsonModule_ProvideGsonFactory(module);
}
public static Gson provideGson(GsonModule instance) {
return Preconditions.checkNotNullFromProvides(instance.provideGson());
}
}
这里DoubleCheck 是 Dagger2 中的一个工具类,用于确保依赖只被创建一次,具体来说,由于我们在注入器接口中标记了被注入参数的作用域,所以会调用DoubleCheck方法。紧接着我们看GsonModule_ProvideGsonFactory,很显然实现调用了create方法,但是create方法又是实际调用了GsonModule_ProvideGsonFactory的构造方法,这里传入了GsonModule类,还记得GsonModule类吗?正是我们自己写的实例提供者。
现在我们继续返回到ActivityComponentImpl中,看这个GsonModule的实例在哪里,答案在builder中。我们先一个一个往前捋:
首先在initialize方法中调用了create:
this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam))
所以我们需要看initialize方法中传入的GsonModule实例来自哪里,是来自ActivityComponentImpl的构造方法中:
private ActivityComponentImpl(GsonModule gsonModuleParam,
SwordmanComponent swordmanComponentParam) {
this.swordmanComponent = swordmanComponentParam;
initialize(gsonModuleParam, swordmanComponentParam);
}
那这个构造方法中的GsonModule来自哪里呢,之前我们提到过,由于这个构造方法是私有的,所以我们只能通过构造器builder来创建,所以答案显然是在builder这个内部类中:
public ActivityComponent build() {
if (gsonModule == null) {
this.gsonModule = new GsonModule();
}
Preconditions.checkBuilderRequirement(swordmanComponent, SwordmanComponent.class);
return new ActivityComponentImpl(gsonModule, swordmanComponent);
}
这个GsonModule类的实例正是调用了我们写的GsonModule的构造方法,所以我们可以画出传递的流程图:
简要流程图(仅适用于本示例)
简而言之,Dagger2正是通过APT和生成的中间件代码来实现依赖注入的。