依赖注入

575
0
0
最后修改于

前面在 IOC Container 一节中已经提到了什么是依赖注入,此处不再过多赘述。

简单来说,依赖注入是一种编程范式 / 思想,在许多编程语言的工程体系中都有所运用。其主要目的是将依赖的准备工作交给外部,当前类只需要关注其自身的主要功能即可。

本节仅简单介绍具体到 JVM / Spring 体系中,依赖注入的三种方式。

Setter 注入#
class SimpleService {

    private lateinit var simpleDep:SimpleDep
  
    fun setSimpleDep(simpleDep:SimpleDep) {  
        this.simpleDep = simpleDep
    }
}

即先创建 SimpleService,再调用 setter 方法进行设置依赖。

这种注入方式暴露了 setter,变量是完全可变的,这在有些情况下是难以接受的。

私有变量注入#

对于 Spring 而言,结合@Autowired/@Resource注解通过反射功能对该样板代码进行了简化。

class SimpleService {
	@Autowired
    private lateinit var simpleDep:SimpleDep
}

这种注入方式的特点是,先创建实例,再反射修改私有变量注入依赖。
优点:这种方式看起来很简单、优雅。
缺点:这使得这个类会强依赖于 IoC / DI 容器

尽管可以移除private修饰符,以自行赋值,但是这会导致封装、可变等其他问题。

构造参数注入#

构造参数注入即在对象创建时就注入依赖。

class SimpleService(private val simpleDep:SimpleDep)

相比于前两种方式,此种方法同时兼具了封装不可变两个方面,具备良好的安全性,可以避免循环依赖等问题。

对于 setter 方式,提供了封装性,但是值是可变的。

对于私有变量注入的方式,则是既非封装,值也可变,完全是通过反射进行的变更。Spring 可以进行这样的变更,那么调用者也就同样可以进行反射。
这两者均有可能导致循环依赖的问题。

一些值得参考的原则#

  • 在大规模多人合作项目中,应当优先采用构造参数注入的方式
  • 在单测场景下,适合采用私有变量注入
  • 应尽量避免循环依赖,如果实在无法避免,可以适度使用setter注入,但仍应该避免使用私有变量注入