Dagger2详解(原理)

Dagger2

Daggger2是啥

Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of an earlier versioncreated by Square and now maintained by Google. Dagger aims to address many of the development and performance issues that have plagued reflection-based solutions. More details can be found in this talk(slides) by +Gregory Kick

翻译:
Dagger是为Android和Java平台提供的一个完全静态的,在编译时进行依赖注入的框架,原来是由Square公司维护的然后现在把这堆东西扔给Google维护了。Dagger解决了基于反射带来的开发和性能上的问题(因为Dagger并没有用反射来做依赖注入)

依赖注入

就是==目标类==(目标类需要进行依赖初始化的类,下面都会用目标类一词来指代)中所依赖的其他的类的初始化过程,通过技术手段可以把其他的类的已经初始化好的实例自动注入到目标类中。

依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的。

举个例子:

我们在写面向对象程序时,往往会用到组合,即在一个类中引用另一个类,从而可以调用引用的类的方法完成某些功能,就像下面这样.

    public class ClassA {

    ClassB b;

    public ClassA() {
    b = new ClassB();
    }

    public void do() {

    b.doSomething();

    }
    }

依赖注入的几种方式

1. 通过接口注入
    interface ClassBInterface {
            void setB(ClassB b);
        }

        public class ClassA implements ClassBInterface {
            ClassB classB;
            @override
            void setB(ClassB b) {
                classB = b;
            }
        }
2. 通过set方法注入
    public class ClassA {
            ClassB classB;

            public void setClassB(ClassB b) {
                classB = b;
            }
        }
3. 通过构造方法注入
     public class ClassA {
            ClassB classB;

            public void ClassA(ClassB b) {
                classB = b;
            }
4. 通过Java注解
public class ClassA {
//此时并不会完成注入,还需要依赖注入框架的支持,如Dagger2
      @inject
      ClassB classB;
    }

在Dagger2中用的就是最后一种注入方式,通过注解的方式,将依赖注入到==宿主类==中

注解

参考:

深入理解Java:注解(Annotation)自定义注解入门

Java 注解 Dependency injection

深入Java Annotation注解

dagger2的使用

引入Dagger2

首先,我们需要将Dagger2的依赖写入我们的gradle中,具体配置如下:

    apply plugin: 'com.neenbedankt.android-apt'

    buildscript {
    repositories {
    jcenter()
    }
    dependencies {
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
    }

    dependencies {
   compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
    }

把 apply plugin和dependencies放在app的gradle里,把buildscript放在项目的gradle里即可,之后我们就可以开始Dagger之旅了。

注解的使用

看过Dagger2的人应该都知道,Dagger2是通过注解来实现依赖注入的,所以,在使用Dagger2之前,我们需要了解这些注解的含义,如果对注解是什么还不清楚的同学可以Google一下,在这就不细说了。Dagger2中主要有6种注解,我们把它拆为4+2,
前四种通俗易懂,后两种理解起来就有一定难度了。

四个基础

这里说的四个基础,指的是四种基础的注解,他们分别是:

  • @Inject Inject主要有两个作用,一个是使用在构造函数上,通过标记构造函数让Dagger2来使用(Dagger2通过Inject标记可以在需要这个类实例的时候来找到这个构造函数并把相关实例new出来)从而提供依赖,另一个作用就是标记在需要依赖的变量让Dagger2为其提供依赖。

  • @Provide 用Provide来标注一个方法,该方法可以在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Injection的变量赋值。provide主要用于标注Module里的方法

  • @Module 用Module标注的类是专门用来提供依赖的。有的人可能有些疑惑,看了上面的@Inject,需要在构造函数上标记才能提供依赖,那么如果我们需要提供的类构造函数无法修改怎么办,比如一些jar包里的类,我们无法修改源码。这时候就需要使用Module了。Module可以给不能修改源码的类提供依赖,当然,能用Inject标注的通过Module也可以提供依赖

  • @Component Component一般用来标注接口,被标注了Component的接口在编译时会产生相应的类的实例来作为提供依赖方和需要依赖方之间的桥梁,把相关依赖注入到其中。

这些标注看起来可能比较抽像,为了方便各位理解,送图一张来说明这些标注的作用和之间的关系:

图片主要分为三部分,左边的是依赖提供者,比如我们用Module标注的类或者用Injection标注的构造函数,右边的是依赖的需求方,例如我们用inject标注的变量,而Component则是连接两者的桥梁,Component从依赖提供者提供依赖,并把这些依赖注入相关的类中,Dagge正如其名,就像把匕首让依赖能够非常犀利的注入到需要它的地方。

说了那么多前言,虽然这些注解都有各自独特的作用,单用起来其实很简单,接下来我们将进一步地讲解这些标注的作用,just show you code。在使用之前,只要大致明白这些标注的意义就行了,简单的依赖注入通过这几个标注就能完成。

例子

组装一台电脑。
电脑需要什么原料呢?
需要显示器(Display)、键盘(keyboard)、主机(Master),也就是依赖
1. 三个依赖类

    public class Display {
        private static final String TAG = "Display";
        public Display() {
           // Log.d(TAG, "Display() called");
            System.out.println("这是个显示器");
        }
    }



    public class keyboard {
        private static final String TAG = "keyboard";

        private String from;

        public keyboard() {

            System.out.println("这是键盘");
        }

        public keyboard(String from) {
            this.from = from;
            System.out.println("这是产自" + from + "的键盘");
        }

    }



    public class Master {
        public Master() {
        }
        @Inject
        public Master(@Named("taste") String string) {
            System.out.println("这是" + string + "Master");
        }
    }

2. ComputerModule 管理原料的module

@Module
public class ComputerModule {

    private String from;

    private String taste;

    @Provides
    public Display providerDisplay() {
        return new Display();
    }

    @Provides
    public String providerString() {
        return from;
    }

    @Named("taste")
    @Provides
    public String providerStringtaste() {
        return taste;
    }

    public ComputerModule() {
    }

    public ComputerModule(String from, String taste) {
        this.from = from;
        this.taste = taste;
    }

    @Provides
    public keyboard providerkeyboardFrom(String from) {
        return new keyboard(from);
    }
}

ComputerdModule相当于工厂这里实例化了==依赖类==,Module管理所有的依赖就好比:你要组装一台电脑需要键盘,显示器,主机原料,module生产并管理这些原料,给其他对象使用
3. 增加一个接口ComputerComponent

         @Component(modules = {ComputerModule.class})//指明要在那些Module里寻找依赖
        public interface ComputerComponent {
            //注意:下面这三个方法,返回值必须是从上面指定的依赖库SaladModule.class中取得的对象
            //注意:而方法名不一致也行,但是方便阅读,建议一致,因为它主要是根据返回值类型来找依赖的
            //★注意:下面这三个方法也可以不写,但是如果要写,就按照这个格式来
            //但是当Component要被别的Component依赖时,
            //这里就必须写这个方法,不写代表不向别的Component暴露此依赖
            Display sprovideDisplay();

            keyboard ProvidekeyBoard();

            Master provideMaster();
            //注意:下面的这个方法,表示要将以上的三个依赖注入到某个类中
            //这里我们把上面的三个依赖注入到Computer中
            //因为我们要做沙拉
            void inject(Computer computer);
        }

ComputerComponent就像工厂管理员,高度目标类我有那些原料.并把这些原料运送给==目标类==.
4. 目标类 Computer

       public class Computer {
   
            @Inject
            Display display;
            @Inject
            keyboard keyboard;
    
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值