Dagger2是目前流行的一个依赖注入框架。使用它可以降低我们程序中类与类之间的耦合。类实例的创建,初始化,销毁及相互依赖都交由dagger2来管理。我们只需要专注于类本身的业务逻辑,提高我们编写程序的便利性。
传统MVP案例
MVP是我们项目中经常使用的一个应用框架。Model层负责具体的业务逻辑,View层负责界面的展示,Presenter层负责协调Model层与View层,通过调用Model层的业务方法,更新View层的界面展示。现在假如我们由这样一个需求:要求我们获取一段信息在界面上展示。应用MVP框架,我们可以这样实现:
/ * 定义一个View层的统一接口 */ public interface IView {
void updateUI(String text); } / * View层,负责界面的展示 */ public class TestActivity extends AppCompatActivity implements IView {
TestPresent mPresent;//Present层实例 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); mPresent=new TestPresent(this);//创建Present层的实例 mPresent.updateUI();//调用Present层的更新UI的方法 } @Override public void updateUI(String text) { ((TextView)findViewById(R.id.textview)).setText(text); } } / * Present类,调用Model层的业务方法,更新View层的界面展示 */ public class TestPresent {
IView mView;//View层实例 TestModel mModel;//Model层实例 //构造方法,传入View层的实例 public TestPresent(IView view){ this.mView=view; this.mModel=new TestModel();//创建Model层的实例 } //更新UI的方法 public void updateUI(){ mView.updateUI(mModel.getText());//调用Model层是业务逻辑,更新View层的界面展示 } } / * Model类,实现具体的业务逻辑 */ public class TestModel {
public TestModel(){ } //返回需要展示的信息 public String getText(){ return "Dagger2应用实践..."; } }
通过以上代码,我们顺利的通过MVP框架实现了我们的需求,代码模块间分工明确,各模块只负责自己本模块的工作。但是这里有一个问题,模块之间相互依赖,一个模块都要依赖其它的模块才能完成实际的功能。根据单一职责原则,一个内聚性高的类,应该只做自己类本身的工作,在需要使用其它的类时,我们只要调用类实例的方法就可以了,实例的创建,初始化,销毁等工作,则不应该由本类负责。通过依赖注入框架,我们就可以只关注类本身的工作,依赖类的创建,初始化,销毁等工作,统统交给依赖注入框架来处理。
Dagger2案例
Dagger2是通过apt根据注解在编译时生成额外的代码实现依赖注入,所以要使用dagger2,首先我们需要在build.gradle(Project:xxx)中配置apt插件:
dependencies { classpath 'com.android.tools.build:gradle:2.3.3' //添加apt插件 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' }
在build.gradle(Module:app)中添加添加dagger2依赖:
apply plugin: 'com.android.application' //添加如下代码,应用apt插件 apply plugin: 'com.neenbedankt.android-apt' ... dependencies { ... //dagger2 compile 'com.google.dagger:dagger:2.4' apt 'com.google.dagger:dagger-compiler:2.4' //java注解 compile 'org.glassfish:javax.annotation:10.0-b28' }
使用Dagger2注解修改各个类:
/ * 定义一个View层的统一接口 * View接口保持不变 */ public interface IView {
void updateUI(String text); } / * View层,负责界面的展示 */ public class TestActivity extends AppCompatActivity implements IView{
//当一个成员变量被@Inject注解修饰,并且它的类型构造函数也被@Inject注解修饰,dagger2就会自动实例化该成员类型,并注入到该成员变量 @Inject TestPresent mPresent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); DaggerTestComponent.builder().testModule(new TestModule(this)).build().inject(this);//@Component负责连接起@Inject和@Module注解 mPresent.updateUI(); } @Override public void updateUI(String text) { ((TextView)findViewById(R.id.textview)).setText(text); } } / * Present类,调用Model层的业务方法,更新View层的界面展示 */ public class TestPresent {
IView mView; @Inject TestModel mModel;//Dagger2遇到@Inject标记的成员属性,就会去查看该成员类的构造函数,如果构造函数也被@Inject标记,则会自动初始化,完成依赖注入。 //TestPresent的构造函数也被@Inject注解修饰 @Inject public TestPresent(IView view){ this.mView=view; } public void updateUI(){ mView.updateUI(mModel.getText()); } } / * Model类,实现具体的业务逻辑 */ public class TestModel {
//构造函数用@Inject修饰 @Inject public TestModel(){ } public String getText(){ return "Dagger2应用实践..."; } } / * Module类提供那些没有构造函数的类的依赖,如第三方类库,系统类,接口类 */ @Module public class TestModule {
private IView mView; public TestModule(IView iView){ this.mView=iView; } //@Provides注解的方法,提供IView类的依赖。 @Provides public IView provideIView(){ return this.mView; } } / *Component必须是一个接口类或者抽象 */ @Component(modules = TestModule.class) public interface TestComponent {
void inject(TestActivity testActivity); }
总结:
- @Inject 如果一个成员变量被@Inject注解修饰,并且它的类型构造函数也被@Inject注解修饰,那么dagger2就可以帮我们实例化该成员类型,并注入。例如:TestActivity类中的mPresent以及TestPresent类中的mModel,都属于这种情况。
- @Module 注解修饰的类负责提供那些没有构造函数的类的依赖,如第三方类库,系统类,接口类。
- @Provides 注解修饰的方法,必须以provide开头后跟提供的依赖类型。负责提供具体类型的依赖,一个@Module修饰的类可以有多个@Provides修饰的方法。
- @Component 注解修饰的接口或抽象类,负责在@Inject和@Module之间建立连接,当实例化@Inject注解的类时,遇到没有构造函数的成员变量依赖,则该依赖由@Module修饰的类提供。inject方法用于获取TestActivity的实例。
看到这里小伙伴们大概已经知道如何使用dagger2了。但对于代码为何这样写,dagger2内部是怎么帮我们实现各个类间的依赖注入的还不是很清楚。接下来,我们就进入到dagger2为我们生成类的源码中看看,dagger2分别为我们实现了那些类,这些类之间是如何协作来帮助我们实现依赖注入的。
Dagger2原理分析
DaggerTestComponent.builder().testModule(new TestModule(this)).build().inject(this);//@Component连接起@Inject和@Module的关键
DaggerTestComponent,这是什么鬼,我们好像没有定义过这个类啊,别急,这个dagger2根据@Component注解帮我们生成的类,我们进去看看它具体做了什么工作。
DaggerTestComponent源码:
/ 1. dagger2根据@Component注解帮我们生成的类,实现我们定义的TestComponent接口 */ public final class DaggerTestComponent implements TestComponent {
private MembersInjector
testPresentMembersInjector;
//负责注入TestPresent中被@Inject注解修饰的的成员变量的依赖。dagger2会为TestPresent生成一个TestPresent_MembersInjector类,专门负责TestPresent中@Inject注解的依赖注入
private Provider
provideIViewProvider;
//负责注入TestPresent中没有构造函数的成员变量的依赖。dagger2会依据@Component中传入的modules值(示例中为TestModule),为Module类中@Provides修饰的方法(示例中为provideIView)提供一个TestModule_ProvideIViewFactory类
private Provider
testPresentProvider;
//提供TestActivity中TestPresent类型的依赖
private MembersInjector
testActivityMembersInjector;
//负责注入TestActivity中@Inject修饰的成员变量
private
DaggerTestComponent(Builder builder) {
assert builder !=
null; initialize(builder); }
public
static Builder
builder() {
return
new Builder(); }
@SuppressWarnings(
"unchecked")
private
void
initialize(
final Builder builder) {
this.testPresentMembersInjector = TestPresent_MembersInjector.create(TestModel_Factory.create());
//创建TestModel_Factory实例,再根据生成的TestModel_Factory实例创建TestPresent_MembersInjector的实例
this.provideIViewProvider = TestModule_ProvideIViewFactory.create(builder.testModule);
//通过传入的TestModule实例创建TestModule_ProvideIViewFactory的实例
this.testPresentProvider = TestPresent_Factory.create(testPresentMembersInjector, provideIViewProvider);
//根据testPresentMembersInjector和provideIViewProvider创建TestPresent_Factory的实例
this.testActivityMembersInjector = TestActivity_MembersInjector.create(testPresentProvider);
//根据testPresentProvider创建TestActivity_MembersInjector的实例 }
@Override
public
void
inject(TestActivity testActivity) { testActivityMembersInjector.injectMembers(testActivity);
//调用testActivityMembersInjector的injectMembers方法为TestActivity提供依赖注入 }
public
static
final
class Builder {
private TestModule testModule;
private
Builder() {}
public TestComponent
build() {
if (testModule ==
null) {
throw
new IllegalStateException(TestModule.class.getCanonicalName() +
" must be set"); }
return
new DaggerTestComponent(
this); }
//传入TestModule的实例
public Builder
testModule(TestModule testModule) {
this.testModule = Preconditions.checkNotNull(testModule);
return
this; } } }
可以看到,dagger2为TestActivity实现依赖注入的步骤大概如下:
- 根据@Component注解生成Dagger开头的DaggerXxxComponent类(示例中为DaggerTestComponent类)
- 根据@Component注解中传入的modules值(示例中为TestModule.class),在DaggerXxxComponent的静态内部类Builder中生成相应的xxxModule方法,传入Module的实例。
- 实现@Component注解接口XxxComponent(示例中为TestComponent)中的inject方法,传入TestActivity的示例。
此时,dagger2已经通过@Component关联起了@Inject和@Module注解。但是具体是怎么注入的我们还不是很清楚,我们看到inject方法中调用testActivityMembersInjector的injectMembers()方法完成了对TestActivity的依赖注入,我们再看TestActivity_MembersInjector的源码:
/ * dagger2根据TestActivity中的@Inject注解生成的成员注入类 */ public final class TestActivity_MembersInjector implements MembersInjector
{
private final Provider
mPresentProvider;
public
TestActivity_MembersInjector(Provider
mPresentProvider) { assert mPresentProvider !=
null;
this.mPresentProvider = mPresentProvider;
//将create方法中传入的mPresentProvider赋值mPresentProvider }
//mPresentProvider即为DaggerTestComponent中创建的TestPresent_Factory的实例testPresentProvider
public
static MembersInjector
create(Provider
mPresentProvider) {
return
new TestActivity_MembersInjector(mPresentProvider); }
//依赖注入方法,在DaggerTestComponent的inject方法中被调用 @Override
public
void
injectMembers(TestActivity instance) {
if (instance ==
null) {
throw
new NullPointerException(
"Cannot inject members into a null reference"); } instance.mPresent = mPresentProvider.
get();
//通过mPresentProvider的get方法获取到TestPresent的实例并赋值给TestActivity中的mPresent }
public
static
void
injectMPresent(TestActivity instance, Provider
mPresentProvider) { instance.mPresent = mPresentProvider.
get(); } }
可以看到,上面代码中是通过mPresentProvider(TestPresent_Factory的实例)的get方法获取到TestPresent的实例并复制给TestActivity中的mPresent,TestPresent_Factory的源码:
/ * dagger2生成的TestPresent工厂类 */ public final class TestPresent_Factory implements Factory<TestPresent> {
private final MembersInjector
testPresentMembersInjector;
//提供TestPresent中@Inject注解修饰的成员变量的依赖
private
final Provider
viewProvider;
//提供TestPresent中不能被@Inject修饰的成员变量(变量类型没有构造函数或构造函数上无法加@Inject注解)的依赖
public TestPresent_Factory( MembersInjector
testPresentMembersInjector, Provider
viewProvider) { assert testPresentMembersInjector !=
null;
this.testPresentMembersInjector = testPresentMembersInjector; assert viewProvider !=
null;
this.viewProvider = viewProvider; } @Override
public TestPresent get() {
//首先根据传入的viewProvider中的get方法获取到IView实例,创建TestPresent的实例,
// 再通过MemberInjectors.injecMembers方法,为创建的TestPreset实例注入@Inject修饰的成员变量(mModule)
//然后返回创建的TestPresent实例
return MembersInjectors.injectMembers( testPresentMembersInjector,
new TestPresent(viewProvider.get())); }
//此处传入的testPresentMemberInjector即为DaggerTestComponent中创建的TestPresent_MembersInjector的实例
//viewProvider即为DaggerTestComponent中创建的TestModule_ProvideIViewFactory的实例
public
static Factory
create( MembersInjector
testPresentMembersInjector, Provider
viewProvider) {
return
new TestPresent_Factory(testPresentMembersInjector, viewProvider); } }
TestPresent_Factory中通过viewProvider的get方法获取到IView的实例,此处的viewProvider即为DaggerTestComponent中传入的TestModule_ProvideIViewFactory实例:
/ * dagger2为@Module修饰的类中的每个@Provides修饰的方法生成的类 */ public final class TestModule_ProvideIViewFactory implements Factory<IView> {
private final TestModule module; public TestModule_ProvideIViewFactory(TestModule module) { assert module != null; this.module = module; } @Override public IView get() { return Preconditions.checkNotNull( module.provideIView(), "Cannot return null from a non-@Nullable @Provides method");//通过传入的TestModule实例的provideIView方法获取IView的实例并返回 } //此处的module即为TestActivity中通过DaggerTestComponet.Builder().testModule()方法传入的TestModule实例 public static Factory
create(TestModule module) {
return
new TestModule_ProvideIViewFactory(module); } }
TestPresent_Factory中通过MembersInjectors中的injectMembers方法,为创建的TestPresent注入@Inject修饰的成员变量(mModel)的依赖。MembersInjectors的源码:
public final class MembersInjectors { public static
T
injectMembers(MembersInjector
membersInjector, T instance) { membersInjector.injectMembers(instance);
//membersInjector为DaggerTestComponent中传入的TestPresent_MembersInjector的实例testPresentMembersInjector,实际上调用的是TestPresent_MembersInjector的injectMembers()方法
return instance; } }
TestPresent_MembersInjector的源码:
public final class TestPresent_MembersInjector implements MembersInjector
{
private final Provider
mModelProvider;
public
TestPresent_MembersInjector(Provider
mModelProvider) { assert mModelProvider !=
null;
this.mModelProvider = mModelProvider; }
public
static MembersInjector
create(Provider
mModelProvider) {
//mModelProvider为DaggerTestComponent中传入的TestModel_Factory的实例
return
new TestPresent_MembersInjector(mModelProvider); } @Override
public
void
injectMembers(TestPresent instance) {
if (instance ==
null) {
throw
new NullPointerException(
"Cannot inject members into a null reference"); } instance.mModel = mModelProvider.
get();
//通过mModelProvider的get方法获取到TestModel的实例并赋值给TestPresent实例中的mModel。 }
public
static
void
injectMModel(TestPresent instance, Provider
mModelProvider) { instance.mModel = mModelProvider.
get(); } }
TestModel_Factory源码:
public enum TestModel_Factory implements Factory
{ INSTANCE;
@Override
public TestModel
get() {
return
new TestModel();
//返回TestModel的实例 }
public
static Factory
create() {
return INSTANCE;
//返回TestModel_Factory的实例 } }
至此,我们完整分析了Dagger2为我们实现依赖注入的全过程,相信大家对Dagger2为我们实现依赖注入的原理有了一定的了解。有什么不解的欢迎大家在评论区给我留言,我会尽量作答。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/218156.html原文链接:https://javaforall.net
