天天看点

Spring干货集|Bean依赖你又觉得行了?(下)

2.2 setter注入

通过调用无参构造器或无参静态工厂方法实例化bean后,通过容器在bean上调用setter方法来完成基于setter注入。

如下案例是一个不依赖于特定于容器的接口,基类或注解,而且只能setter注入方式DI的POJO类。

Spring干货集|Bean依赖你又觉得行了?(下)

ApplicationContext为其管理的bean的提供了构造器和setter DI的支持。也支持在已通过构造器注入某些依赖后,还支持setter DI。可通过BeanDefinition的形式配置依赖项,将其与PropertyEditor实例结合使用,以将属性从一种格式转为另一种。但大多数开发者并非以编程方式直接使用这些类,而是使用

XML形式的 bean定义

带注解的组件,即被@Component,@Controller等注解的类

基于Java的@Configuration类中的@Bean方法

然后将这些源在内部转换为BeanDefinition实例,并用于加载整个IoC容器实例。

3 构造器注入还是 setter 注入呢?

这么详细地分别介绍完后,那么到底哪种 DI 方式好呢?

由于可混用构造器和setter DI,因此将构造器用于强制性依赖项,并搭配将setter方法或配置方法用于可选依赖项是个很好的最佳实践。

注意,可在setter方法上使用@Required注解,以使该属性成为必需的依赖;但最好使用带有编程式验证的参数的构造器注入。

而且注意,Spring团队推荐构造器注入,因为它可以让开发者将应用的组件实现为不可变对象,并确保所需的依赖项不为null。此外,构造器注入的组件始终以完全初始化的状态返回给客户端(调用)代码。不过注意了哦,大量的构造器自变量是一种坏代码,因为这意味着该类可能承担了太多职责(违反单一职责的编程原则),应对其重构以更好地解决关注点的解耦问题。

Setter注入主要应仅用于可以在类中分配合理的默认值的可选依赖项。否则,必须在代码使用依赖项的所有地方都执行判空检查。setter注入的一个好处是,setter方法使该类的对象在以后可重新配置或注入。

使用对特定类最有意义的DI方案。有时,在处理没有源代码的第三方类库时,将为你做出选择。例如,若第三方类库未公开任何setter方法,则构造器注入可能就是DI的唯一可用方案咯。

4 deponds-on 属性有何用?

你以为这个东西面试没人问?看图!

Spring干货集|Bean依赖你又觉得行了?(下)

若一个bean是另一个的依赖,则通常意味着将一个bean设为另一个的属性。通常可使用XML形式配置元数据中的<ref/>元素完成此操作。但有时bean之间的依赖关系不那么直接。一个示例是何时需要触发类中的静态初始化器,例如用于数据库驱动程序注册。depends-on属性可显式强制初始化一或多个使用该元素的bean之前的bean。

看如下案例,使用depends-on属性表示对单个bean的依赖关系:

Spring干货集|Bean依赖你又觉得行了?(下)
要表示对多个 bean 的依赖,请提供 bean 名称列表作为依赖属性的值(逗号、空格和分号都是有效的分隔符):
Spring干货集|Bean依赖你又觉得行了?(下)

depends-on属性既可以指定一个 初始化期(initialization-time) 依赖项,也可指定一个对应的析构期(destruction-time)依赖项。在销毁给定bean之前,首先销毁定义与给定bean的依赖关系的依赖bean。因此,depends-on还可以用来控制关闭顺序。

5 lazy-init属性有何作用?

在默认的初始化过程中,ApplicationContext会及早地创建并配置所有的单例bean。一般来说,这种预实例化是有好处的,毕竟相比于若干天后的亡羊补牢,这样可立即发现配置或上下文环境的错误。

当然了,如果你的业务决定了不想要这种默认行为,也可将bean定义标记为延迟初始化来防止对单例bean的预实例化。延迟初始化的bean告诉IoC容器在首次请求时而不是在应用启动阶段就创建一个bean实例。

如下案例:

XML形式,通过<bean/>标签内的lazy-init属性控制

Spring干货集|Bean依赖你又觉得行了?(下)
注解形式
Spring干货集|Bean依赖你又觉得行了?(下)
无需多虑,默认值为true就是要延迟初始化。
Spring干货集|Bean依赖你又觉得行了?(下)

当上述的配置被  ApplicationContext 使用时,在 ApplicationContext 启动时不会预实例化惰性bean,未使用该属性的非惰性bean才会被预实例化。

不过需要注意的是,当lazy-init bean是未lazy-init的单例bean的依赖时,ApplicationContext在启动阶段还是会创建lazy-init bean,因为它必须要满足单例的依赖关系,lazy-init bean会被注入到其它未lazy-init 的单例bean中。

另外如果需要,可通过<bean/>标签内的 default-lazy-init 属性控制容器级别的延迟初始化,案例如下:

Spring干货集|Bean依赖你又觉得行了?(下)
参考