Dagger2与依赖注入

414 阅读3分钟

什么是依赖注入?

  • 就是目标类中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建
  • 不要在需要依赖的类中通过new来创建依赖而是通过方法提供的参数注入进来

常用四种依赖注入方式

  1. 常用方式,接口方法实现
interface ClassBInterface {
    void setB(ClassBInterface b);
}

class ClassAInterface implements ClassBInterface {
    ClassBInterface classB;

    @Override
    public void setB(ClassBInterface b) {
        classB = b;
    }
}
  1. set方式成员变量赋值
public class ClassAset{
    ClassB classB;
    public void setClassB(ClassB b){
        classB = b;
    }
}
  1. 构造器注入
public classAConstructor{
    ClassB classB;
    public ClassAConstructor(ClassB b){
        classB = b;
    }
}
  1. 注解方式,动态注入,FruitContainerInject不用关心Fruit具体实现
    • 以dagger2为例,可以理解为Dagger2就是一个帮助我们写工厂代码的工具
public class FruitContainerInject{
    @Inject
    Fruit f;
    public FruitContainerInject(){
        
    }
}

@Inject注解

  • 1 一个是标记在需要依赖的变量
    public class Car{
        @Inject
        Tyre tyre;
        public Car(){
            DaggerCarComponent.builder().build().injectCar(this);
        }
    }
    
  • 2 使用在构造函数上
    public class Tyre{
        @Inject
        public Tyre(){
            
        }
    }
    
  • 结论:
    • 依赖注入是依赖的对象实例一>需要注入的实例属性
    • 新建工厂实例并调用成员属性注入类完成Tyre的实例注入

@Component注解

  • 可以标注接口或抽象类
  • 可以完成依赖注入过程
@Component
public interface CarComponent{
    void injectCar(Car car);
}

dagger2的inject和component注解实例和源码分析

我们想要将Student注入到College类,传统写法是这样的 ``` class OldCollege { Student student;

    public OldCollege(Student student) {
        this.student = student;
    }
}
```

使用dagger2可以这样

  • 首先将Student注入College
    class College {
        @Inject
        Student student;
    
        public College() {
            DaggerCollegeComponent.builder().build().inject(this);
        }
    }
    
  • 为了能够确定是哪个构造方法创建的Student实例,需要在需要的构造方法上加上@Inject注解
    class Student {
        private int id;
        private String name;
    
        @Inject
        public Student() {
            System.out.println("Student create");
        }
    
        public Student(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }
    
  • 现在College需要使用Student,为了链接这两个类,需要一个桥梁
    @Component
    interface CollegeComponent {
        void inject(College college);
    }
    

原理分析

  • 最终是通过工厂方法创建了Student实例

@Module和@Provides注解

@Injetc的问题:无法修改提供的类的构造函数,如jar包中的类,我们无法修改其源码

@Module可以给不能修改源码的类提供依赖,需要配合@Provides使用

  • @Provide标注一个Module中的方法
  • 步骤
    • ①创建Module
    • ②指明Component需要的Module
    @Module
    public class CarModule {
        @Provides
        static Car provideCar(){
            return new Car();
        }
    }
    
    @Component(modules = CarModule.class)
    interface CarComponent {
        void injectCar(Car car);
    }
    
    

完整示例

  • 这段代码中既有inject注解的构造方法,又有Provides提供的构造方法
  • 最终实际上是根据注解生成了不同改造函数的Student实例
@Module
public class CollegeModule {
    @Provides
    ClassRoom provideClassRoom(){
        return new ClassRoom();
    }

    @Provides
    Student provideStudent(ClassRoom classRoom){
        return new Student(classRoom);
    }
}

@Component(modules = CollegeModule.class)
interface CollegeComponent {
    void inject(College college);
}

class College {
    @Inject
    Student student;

    public College() {
        DaggerCollegeComponent
                .builder()
                .collegeModule(new CollegeModule())
                .build()
                .inject(this);
    }
}


class Student {
    private int id;
    private String name;
    private ClassRoom classRoom;

    @Inject
    public Student() {
        System.out.println("Student create");
    }

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Student(ClassRoom classRoom) {
        this.classRoom = classRoom;
    }
}