spring-core-2-20 | 构造器注入 VS. Setter 注入:为什么Spring官方文档的解读会与作者的初心出现偏差

本文主要是介绍spring-core-2-20 | 构造器注入 VS. Setter 注入:为什么Spring官方文档的解读会与作者的初心出现偏差,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

构造器注入VS. Setter 注入

Spring Framework 对构造器注入与Setter 的论点:

来自“Constructor-based or setter-based DI”

“The Spring team generally advocates constructor injection, as it lets
you implement application components as immutable objects and ensures that required dependencies are not null.

Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later.
Management through JMX MBeans is therefore a compelling use case for setter injection.”

这里spring团队以一个讨论的口吻来说的, 建议一般使用构造器注入, 保证注入的对象是一个immutable, 不变的对象, 确保依赖的对象不为空. 这个讲法忽略了一个细节, 其实如果依赖的对象为空或者不存在的话, 可以用另外的方式, 也可以通过构造器方式进行注入, 使用 ObjectProvider 类, 它是一种类型安全的方式, 如果你的依赖注入或依赖查找的方式需要的是一个单一类型的依赖, 这时可以调用它的 getIfAvailable() ,来进行示范性的返回, 等于空的时候就会返回空, 这种方式在 springBoot的场景中经常被用到.

构造器注入的组件通常返回给客户端代码的时候, 是一个完整的初始化状态. 不过呢, 如果构造器的参数过多, 代码看起来就不是十分的良好, 意味着类包含了太多的职责, 不能有太多的输入, 最好进行一下重构(refactored)

Setter注入应该主要仅用于我们的可选性的注入, 另一方面, 如果代码中有用到相关的依赖, 非空检查就是必须的, 我们都知道@Autowired注解是有非空检查的参数的, 而默认可以注入空的对象过来.当然 Setter 注入可以让依赖进行延迟注入, 让对象变得更可配, 这是一个优点

《Expert One-on-One™ J2EE™ Development without EJB™》认为Setter 注入的优点:

来自“Chapter 6. Lightweight Containers and Inversion of Control” 节选

“Advantages of Setter Injection include:

• JavaBean properties are well supported in IDEs.
JavaBean的属性在IDE方面支持良好, 前面讲过, 在 GUI 方面是有用的.

• JavaBean properties are self-documenting.
JavaBean的属性是 自文档 的方式, 通常不需要过多文档说明

• JavaBean properties are inherited by subclasses without the need for any code.
JavaBean的属性通过继承的方式呢, 通常不需要任何的修改, 但是这个通常不应该是个优点, 只是作为面向对象的一个特点

• It’s possible to use the standard JavaBeans property-editor machinery for type conversions if necessary.
因为有 propertyEditor 这个机制, setter中可以进行一些类型转换

• Many existing JavaBeans can be used within a JavaBean-oriented IoC
container without modification.
大量存在的JavaBeans可以在JavaBean原生的IoC容器中使用, 不需要做太大的修改.
这里就是指的原生的 BeanContext 这个容器, 这个上下文其实和 spring的 ApplicationContext 有异曲同工之处.

• If there is a corresponding getter for each setter (making the property readable, as well as writable), it is possible to ask the component for its current configuration state. This is particularly useful if we want to persist that state: for example, in an XML form or in a database. With Constructor Injection, there’s no way to find the current state.
如果每一个Setter方法都有对应的Getter方法的情况下, 可以比较方便的在任何时候获取到组件的当前状态.这个特点在我们需要保存这个状态的时候特别有用, 而构造器注入就做不到这点. 这样就容易对Bean进行一个管理.

• Setter Injection works well for objects that have default values, meaning that not all properties need to be supplied at runtime.
Setter方法可以为属性设置一个默认值, 并不是所有的属性都需要在运行时才进行设值.

《Expert One-on-One™ J2EE™ Development without EJB™》认为Setter 注入的缺点:

来自“Chapter 6. Lightweight Containers and Inversion of Control” 节选

“Disadvantages include:

The order in which setters are called is not expressed in any contract. Thus, we sometimes need to invoke a method after the last setter has been called to initialize the component. Spring provides the org.springframework.beans.factory.InitializingBean interface for
this; it also provides the ability to invoke an arbitrary init method. However, this contract must be documented to ensure correct use outside a container.
setter的顺序无法保证, 而构造器注入因为构造器方法的参数顺序是一定的, 天然决定了设值的顺序是有序的, 不会因为外部调用的顺序而出现问题.
这里提到了一个spring的接口 InitializingBean ,这个接口能够帮助我们实现一个特性就是当我的属性已经设置好了之后, 我们再做相应的操作. 但是这个接口并不会强制的保证正确性, 只是一个鼓励.

Not all the necessary setters may have been called before use. The object can thus be left partially configured.”
在调用前并不是每一个Setter方法都需要被调用的.

《Expert One-on-One™ J2EE™ Development without EJB™》认为构造器注入的优点:

来自“Chapter 6. Lightweight Containers and Inversion of Control” 节选

“Advantages of Constructor Injection include:

Each managed object is guaranteed to be in a consistent state—fully configured—before it can be invoked in any business methods. This is the primary motivation of Constructor Injection. (However, it is possible to achieve the same result with JavaBeans via dependency checking, as Spring can optionally perform.) There’s no need for initialization methods.
能够确保每个被管理的对象有一致的状态. 完全配置好的, 且一旦初始化完成就不再进行变更的. 正如前面所说, 也因此组件对应的对象通常也被声明为 final 的.

There may be slightly less code than results from the use of multiple JavaBean methods, although will be no difference in complexity.”
减少过多的Setter和Getter方法的代码量. 这个因为现在有建造模式, 似乎也没啥必要.

《Expert One-on-One™ J2EE™ Development without EJB™》认为构造器注入的缺点:

来自“Chapter 6. Lightweight Containers and Inversion of Control” 节选
这里就能看到, 作者一开始书里的观点, 和后来在spring官方网站的观点, 有一些冲突, 这里反而构造器注入的缺点列了一大堆.

“Disadvantages include:

• Although also a Java-language feature, multi-argument constructors are probably less common in existing code than use of JavaBean properties.
多参数构造器可能会减少代码中一些Bean的使用. 啥意思?

• Java constructor arguments don’t have names visible by introspection.
构造器参数没有一个名称是可见的来提供给外部进行外省或内省.

• Constructor argument lists are less well supported by IDEs than JavaBean setter methods.
IDE的支持不如Setter方法的好

• Long constructor argument lists and large constructor bodies can become
unwieldy.

• Concrete inheritance can become problematic.

• Poor support for optional properties, compared to JavaBeans

• Unit testing can be slightly more difficult

• When collaborators are passed in on object construction, it becomes
impossible to change the reference held in the object. ”

这篇关于spring-core-2-20 | 构造器注入 VS. Setter 注入:为什么Spring官方文档的解读会与作者的初心出现偏差的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/714113

相关文章

Spring Boot整合Redis注解实现增删改查功能(Redis注解使用)

《SpringBoot整合Redis注解实现增删改查功能(Redis注解使用)》文章介绍了如何使用SpringBoot整合Redis注解实现增删改查功能,包括配置、实体类、Repository、Se... 目录配置Redis连接定义实体类创建Repository接口增删改查操作示例插入数据查询数据删除数据更

Java Lettuce 客户端入门到生产的实现步骤

《JavaLettuce客户端入门到生产的实现步骤》本文主要介绍了JavaLettuce客户端入门到生产的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录1 安装依赖MavenGradle2 最小化连接示例3 核心特性速览4 生产环境配置建议5 常见问题

Java使用Swing生成一个最大公约数计算器

《Java使用Swing生成一个最大公约数计算器》这篇文章主要为大家详细介绍了Java使用Swing生成一个最大公约数计算器的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下... 目录第一步:利用欧几里得算法计算最大公约数欧几里得算法的证明情形 1:b=0情形 2:b>0完成相关代码第二步:加

Java 的ArrayList集合底层实现与最佳实践

《Java的ArrayList集合底层实现与最佳实践》本文主要介绍了Java的ArrayList集合类的核心概念、底层实现、关键成员变量、初始化机制、容量演变、扩容机制、性能分析、核心方法源码解析、... 目录1. 核心概念与底层实现1.1 ArrayList 的本质1.1.1 底层数据结构JDK 1.7

Java Map排序如何按照值按照键排序

《JavaMap排序如何按照值按照键排序》该文章主要介绍Java中三种Map(HashMap、LinkedHashMap、TreeMap)的默认排序行为及实现按键排序和按值排序的方法,每种方法结合实... 目录一、先理清 3 种 Map 的默认排序行为二、按「键」排序的实现方式1. 方式 1:用 TreeM

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,