Dagger2依赖注入单例化介绍及验证

业务组件单例化其实在现在企业级应用中都有大量应用场景,企业化应用中,频繁创建和销毁对象实例场景下对JVM的开销可以大到不可想象,单例化在减轻JVM内存管理负担、提升应用性能、尤其是在电子商务、大数据应用场景下,大批量、爆发式请求涌入服务器的过程中,如果组件没有做单例化处理,可能直接导致系统崩溃,尤其有些共享JVM的应用甚至会挤爆JVM设定内存导致内存溢出,拖垮其他系统应用,甚至带来整个平台雪崩。这也是企业级应用中对单例化模式大量使用的原因,也是单例化的重要价值所在。

针对Android设备这样少的可怜的性能资源和有相当限度的系统可用开销,对组件单例化的需求自然是如饥似渴一般,相比传统设备,Android系统更经不起开发人员对资源进行挥霍和浪费。Dagger2在接管Ioc的整个过程中,是否能够承接应用对组件单例化的需求也就更加凸显在编码需求中。

定义一个业务类:

package com.tc.app.dagger2.di.singleton;

import android.util.Log;

/**
 *
 * @author min.weixm
 * @version $$Id: Abusiness, v 0.1 2021/11/16 23:17 min.weixm Exp $$
 */
public class Abusiness {

   public Abusiness(){}

   public void display(){
      Log.i("[Abusiness.display()]","Abusiness.display() called");
   }
}

为业务定义一个Module:

package com.tc.app.dagger2.di.singleton;

import dagger.Module;
import dagger.Provides;

/**
 *
 * @author min.weixm
 * @version $$Id: ABusinessModule, v 0.1 2021/11/20 20:33 min.weixm Exp $$
 */
@Module
public class ABusinessModule {


   @Provides
   public Abusiness provideMyBusinessA() {
      return new Abusiness();
   }
}

不失完整性定义一个Component:

package com.tc.app.dagger2.di;

import com.tc.app.dagger2.MainActivity;
import com.tc.app.dagger2.di.singleton.ABusinessModule;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 不真正提供实例,真实实例由 MyBusinessApartModule 提供
 *
 * @author min.weixm
 * @version $Id: MyApartComponent.java, v 0.1 2021/11/12 14:40 min.weixm Exp $
 */
@Component(modules = {ABusinessModule.class})
public interface MyApartComponent {

   void inject(MainActivity activity);
}

接下来我们实际注入我们的业务类,关键代码如下:

/** 通过依赖注入的业务服务实例 */
@Inject
Abusiness abusinessX;

@Inject
Abusiness abusinessY;

通过分别注入业务对象实例,我们方便我们观察两个对象的Hash值是否一致。完整代码如下:

package com.tc.app.dagger2;

import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.tc.app.dagger2.di.DaggerMyApartComponent;
import com.tc.app.dagger2.di.singleton.Abusiness;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {

   /** 通过依赖注入的业务服务实例 */
   @Inject
   Abusiness abusinessX;

   @Inject
   Abusiness abusinessY;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      this.setContentView(R.layout.activity_main);
      Toolbar toolbar = findViewById(R.id.toolbar);
      setSupportActionBar(toolbar);

      FloatingActionButton fab = findViewById(R.id.fab);
      fab.setOnClickListener((view) ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                  .setAction("Action", null).show()
      );

      //初始化环境,并完成功能调用
      DaggerMyApartComponent.create().inject(this);
      Log.i("---------------abusinessX---------------", "" + abusinessX);
      Log.i("---------------abusinessY---------------", "" + abusinessY);
   }

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      getMenuInflater().inflate(R.menu.menu_main, menu);
      return true;
   }

   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      int id = item.getItemId();
      if (id == R.id.action_settings) {
         return true;
      }
      return super.onOptionsItemSelected(item);
   }
}

执行build后,运行结果日志如下:

I/---------------abusinessX---------------: com.tc.app.dagger2.di.singleton.Abusiness@91dbc1d
I/---------------abusinessY---------------: com.tc.app.dagger2.di.singleton.Abusiness@c681e92

通过运行结果,可以看出,Dagger2虽然自动注入了相应的业务实例,但两个对象的Hash值并不一致,实际上是初始化了两个完全不同的实例。为了能够确保注入的对象是单例的,我们开始对Module和Component增加相应的@Singleton标签。

Module代码如下:

package com.tc.app.dagger2.di.singleton;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 *
 * @author min.weixm
 * @version $$Id: ABusinessModule, v 0.1 2021/11/20 20:33 min.weixm Exp $$
 */
@Module
public class ABusinessModule {


   @Provides
   @Singleton
   public Abusiness provideMyBusinessA() {
      return new Abusiness();
   }
}

Component代码如下:

package com.tc.app.dagger2.di;

import com.tc.app.dagger2.MainActivity;
import com.tc.app.dagger2.di.singleton.ABusinessModule;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 不真正提供实例,真实实例由 MyBusinessApartModule 提供
 *
 * @author min.weixm
 * @version $Id: MyApartComponent.java, v 0.1 2021/11/12 14:40 min.weixm Exp $
 */
@Component(modules = {ABusinessModule.class})
@Singleton
public interface MyApartComponent {

   void inject(MainActivity activity);
}

保持注入方式不变,我们build完代码后重新运行一下,结果如下:

I/---------------abusinessX---------------: com.tc.app.dagger2.di.singleton.Abusiness@91dbc1d
I/---------------abusinessY---------------: com.tc.app.dagger2.di.singleton.Abusiness@91dbc1d

神奇的一幕出现了,尽管我们Module中相应业务的实例是new出来的,但是增加完@Singleton标签后,Dagger2注入的实例无论在哪里引入多少次,都能保证业务实例是同一个实例。

上一篇:零基础大数据该学什么?


下一篇:从金融行业转型大数据,一路学习点滴的分享!