业务组件单例化其实在现在企业级应用中都有大量应用场景,企业化应用中,频繁创建和销毁对象实例场景下对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注入的实例无论在哪里引入多少次,都能保证业务实例是同一个实例。