Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Spring字段注入存在哪些问题,你知道吗?

Spring字段注入存在哪些问题,你知道吗?

作者头像
阿凯
发布于 2021-08-19 06:22:25
发布于 2021-08-19 06:22:25
1.3K00
代码可运行
举报
文章被收录于专栏:程序员阿凯程序员阿凯
运行总次数:0
代码可运行

阅读文本大概需要 7 分钟。

Spring字段注入存在哪些问题,你知道吗?

昨天有个同学面试回来向我求助,说面试官问他Spring字段注入存在什么问题,他当时没有回答上来。

是的,Spring的字段注入,是我们最常使用的注入方式,但是却一直存在着隐藏着的问题。

这个问题其实在使用IDEA的时候已经提示我们了,只是大部分时候我们视而不见,或者明明知道,却选择了忽视。

现在我们来仔细看看吧,这是我们经常使用的一个场景,在一个Controller里注入需要使用的Service。

一般我们都是在这个字段上打上Autowired注解,这样就实现了字段注入。

代码很简单,但是你是否注意到 IDEA 给我们在 @Autowired注解下那提示的波浪线呢?

我们把鼠标移上去看一下:

Field injection is not recommended

英文稍微好一点的同学已经知道是什么意思了,这是Spring官方不建议我们这样用啊。

英文稍微没有那么好的也没有关系,我们利用翻译工具看一下:

是的,Spring官方不建议我们使用字段注入的方式,并且建议我们换一种方式。

哈哈,推荐使用构造方法注入。

那么疑问来了,这是为什么呢?

这就要回到咱们最开始的那道面试题了,Spring字段注入存在哪些问题呢?

是的,通过 @Autowired 注解配合字段注入的实现方式,非常简单而直接,代码的可读性也很强。

而且,事实上在我们的开发过程中,字段注入是三种注入方式中最常用、也是最容易使用的一种。

但它也是三种注入方式中最应该避免使用的。

原因有三点:

  1. 注入的对象外部不可见

字段注入的最大问题是就是对象的外部可见性问题。

在前面的 CourseController 类中,我们通过定义一个私有变量 ICourseService 来注入该接口的实例。显然,这个实例只能在 CourseController 类中被访问,脱离了容器环境我们无法访问这个实例。

既,如果我们不是通过Spring容器注入 CourseController 的实例,而是自己直接new对象的方式创建。

那么,结果就是一个 NullPointerException。

原因就在于,无法在 CourseController 的外部实例化 ICourseService 对象。

采用字段注入,类与容器的耦合度过高,我们无法脱离容器来使用目标对象。

这种做法实际上是不符合 JavaBean 开发规范的,而且可能一直无法发现空指针异常的存在。

  1. 循环依赖

字段注入的第二个问题,是可能导致潜在的循环依赖。

我们来看下面这段代码:

这里的 ClassA 和 ClassB 实际上就发生了循环依赖。

上述代码在 Spring 中是合法的,容器启动时并不会报任何错误,只有在使用到具体某个 ClassA 或 ClassB 时才会报错。

而这个时候,往往为时已晚。

  1. 无法保证注入对象不可变

使用字段注入的方式,我们无法设置需要注入的对象为 final,也无法注入那些不可变对象。

这是因为字段注入的对象必须在类实例化后在进行实例,而final修饰的对象必须提前到对象声明的时候或者在构造方法中实例化。

基于以上三点,无论是 IDEA,还是 Spring 官方,都不推荐我们开发人员使用字段注入这种注入模式,而是推荐构造器注入。

在面试中,针对字段注入,请记住它主要的三点缺陷:

不具备外部可见性、会导致循环依赖,以及无法注入不可变对象。

那么,我们有什么办法解决这些问题呢?

这就要回到另一道经典的面试题上来了,如何在 Spring 中注入对象呢?Spring 的依赖注入有哪些呢?

这道题对于我们的同学来说还是比较简单的。

Spring 为开发人员提供了三种不同的依赖注入类型,分别是字段注入构造器注入Setter 方法注入

既然字段注入有问题,那么我们来看一看,其他两种注入方式呢。

构造方法注入

关于构造器注入,面试中往往会以这样的形式考察你:

构造器是 Spring 官方推荐的依赖注入类型,你知道它有哪些特性吗?

或者换种问法,构造器注入相比字段注入的优势在哪里?

构造器注入的形式也很简单,就是通过类的构造函数来完成对象的注入,示例代码如下所示:

可以看到构造器注入能解决对象外部可见性的问题,因为这里的 ICourseService 是通过 CourseController 构造函数进行注入的,所以势必可以脱离 CourseController 而独立存在。

关于构造器注入,我们也建议你引用 Spring 官方文档来向面试官解释它的功能特性。在 Spring 官方文档中有这样一段话:

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.

这段话的核心意思在于:构造器注入能够保证注入的组件不可变,并且确保需要的依赖不为空。

这里的组件不可变也就意味着你可以使用 final 关键词来修饰所依赖的对象,而依赖不为空是指所传入的依赖对象肯定是一个实例对象,避免出现空指针异常。

同时,基于构造器注入,如果存在前面介绍的 ClassA 和 ClassB 之间的循环依赖关系,我们会这样注入对象:

那么,在 Spring 容器启动的时候,就会抛出一个循环依赖异常,从而提醒你避免循环依赖。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'CLassA' defined in file[]: 
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'CLassB' defined in file []: 
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'CLassA': 
Requested bean is currently in creation: 
Is there an unresolvable circular reference?

如此看来,字段注入的三大问题,就都可以通过使用构造器注入的方式来解决。

但是,构造器注入就没有问题了吗?显然不是!

当构造函数中存在较多依赖对象的时候,大量的构造器参数会让代码显得比较冗长。

假设一个类的构造器需要多个参数,那么我们想要使用这个类时,就需要事先准备好这些参数,并严格按照构造器指定的顺序一一进行传入。

那么,无论从代码的可读性还是可维护角度而言,这都不是很符合最佳实践。

这时候就可以引入 Setter 方法注入。

Setter 方法注入

Setter 方法注入和构造器注入看上去有点类似,而且它比构造函数更具可读性。

我们可以把多个依赖对象分别通过 Setter 方法逐一进行注入。

另一方面,Setter 方法可以很好解决应用程序中的循环依赖问题,如下所示,通过 Setter 方法注入的ClassA 和 ClassB 代码是可以正确执行的:

而且,通过 Setter 注入,还可以对依赖对象进行多次重复注入,这在构造器注入中是无法实现的。

最后,概括起来就是:

*构造器注入适用于强制对象注入,注入的对象是不可变的

*Setter 注入适合于可选对象注入,可以解决循环依赖问题

*字段注入应该避免,对象无法脱离 Spring容器而独立运行,。

好了,现在你能回答出三种依赖注入类型的相关内容了,依赖注入用得好,Spring 框架面试轻松搞定。

优秀啊,骚年!后期更多优选推文,各种资料、分享猛料放出,关注公众号,获取实时动态:

大家还有什么需求,也可以后台留言给我,公众号上还有其他学习资源哦....

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员阿凯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【源码分析】Spring依赖注入原理
在Spring中提供了三种实现依赖注入的方式:字段注入、构造器注入、Setter方法注入。
百思不得小赵
2022/12/01
6170
【源码分析】Spring依赖注入原理
测试一下25道Spring经典面试题你会几道?循环依赖面试详解
当一个ClassA依赖于ClassB,然后ClassB又反过来依赖ClassA,这就形成了一个循环依赖:
程序员追风
2019/07/29
3520
测试一下25道Spring经典面试题你会几道?循环依赖面试详解
Spring高频面试题:如何解决循环依赖问题!
那Spring到底是如何解决的setter方法依赖注入引起的循环依赖问题呢?请看下图(其实主要是通过两个缓存来解决的):
会呼吸的Coder
2020/11/26
4K0
Spring高频面试题:如何解决循环依赖问题!
Spring高频面试题:如何解决循环依赖问题!
那Spring到底是如何解决的setter方法依赖注入引起的循环依赖问题呢?请看下图(其实主要是通过两个缓存来解决的):
业余草
2020/11/26
4730
Spring高频面试题:如何解决循环依赖问题!
大公司为什么禁止在 Spring Boot 项目中使用 @Autowired 注解?
查阅了相关文档了解了一下,原来这个提示是spring framerwork 4.0以后开始出现的,spring 4.0开始就不推荐使用属性注入,改为推荐构造器注入和setter注入。
搜云库技术团队
2023/08/08
5100
大公司为什么禁止在 Spring Boot 项目中使用 @Autowired 注解?
极简SpringBoot指南-Chapter02-Spring依赖注入的方式
w4ngzhen/springboot-simple-guide: This is a project that guides SpringBoot users to get started quickly through a series of examples (github.com)
w4ngzhen
2023/10/17
3130
【Spring】如何解决Spring的循环依赖问题?这道面试题助我拿到了Offer!!
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
6270
【Spring】如何解决Spring的循环依赖问题?这道面试题助我拿到了Offer!!
美团一面:为什么 Spring 和 IDEA 都不推荐使用 @Autowired 注解??
大家在使用IDEA开发的时候有没有注意到过一个提示,在字段上使用Spring的依赖注入注解@Autowired后会出现如下警告:
良月柒
2024/04/18
3111
美团一面:为什么 Spring 和 IDEA 都不推荐使用 @Autowired 注解??
Spring官网阅读系列(二):Spring依赖注入及方法注入
上篇文章我们学习了官网中的1.2,1.3两小节,主要是涉及了容器,以及Spring实例化对象的一些知识。这篇文章我们继续学习Spring官网,主要是针对1.4小节,主要涉及到Spring的依赖注入。虽然只有一节,但是涉及的东西确不少。话不多说,开始正文。
秃顶的Java程序员
2020/03/24
4440
【Spring】浅谈spring为什么推荐使用构造器注入
一、前言 ​ Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合。前几天的时候,笔者的同事问我为什么要使用构造器的注入方式,我回答说因为Spring文档推荐这种,而说不出为什么 T^T,后面抽时间了解了一下,下面就是笔者要讨论的就是其注入方式。 二、常见的三种注入方式 ​ 笔
joemsu
2018/05/17
2K0
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring绝对是我们日常开发中使用频次最高的框架之一。它灵活的依赖注入机制为我们开发高可维护性的代码提供了极大的便利。然而,尽管@Autowired注解让依赖注入变得如此简单,Spring官方却明确不推荐在字段上使用它进行注入。那么,为什么会这样?今天,我们就来深入探讨一下这个问题。
阿珍
2024/10/15
3030
为什么Spring不推荐@Autowired用于字段注入?
依赖注入和循环依赖注入
1.java bean注入的两种方式 1.1 Resource注解方式 @Resource private NestedComponent nestedComponent2; 1.2 构造器注入的方式来 private NestedComponent nestedComponent1;
oktokeep
2024/11/21
1060
Spring如何管理Bean的生命周期呢?
我们都知道,在面试的过程中,关于 Spring 的面试题,那是各种各样,很多时候就会问到关于 Spring的相关问题,比如 AOP ,IOC 等等,还有就是关于 Spring 是如何管理 Bean 的生命周期的相关问题,今天了不起就来和大家一起看看 Spring 是如何管理 Bean 的生命周期的。
Java极客技术
2024/05/28
1320
Spring如何管理Bean的生命周期呢?
Spring系列三:IoC 与 DI
在软件工程中,控制反转(IoC)是一种设计思想,对象之间耦合在一起,在运行时自动绑定,并且它们编译时对所需要引用的对象是不确定的。在这个spring教程中,通过示例了解ioc和spring中的依赖注入之间的区别。
java干货
2021/02/19
6380
Spring系列三:IoC 与 DI
Spring的Bean注入方式
在这个例子中,UserService 类通过构造方法接受一个 UserRepository 的实例。当创建 UserService 对象时,将传入一个 UserRepository 实例,这就是构造方法注入。
酒楼
2023/11/13
3220
给学妹看的SpringIOC 面试题(下)
之前上篇跟学弟学妹讲了一下SpringIOC的启动流程,今天接着给学妹聊聊DI—Dependency Injection(依赖注入)
敖丙
2021/09/16
4280
Spring为什么建议构造器注入?
本章的内容主要是想探讨我们在进行Spring 开发过程当中,关于依赖注入的几个知识点。感兴趣的读者可以先看下以下问题:
Java旅途
2021/07/13
1.7K0
Spring Framework中的依赖注入:构造器注入 vs. Setter注入
构造器注入和Setter注入是依赖注入(Dependency Injection,DI)中两种常见的方式,用于向一个对象注入其所依赖的其他对象或数值。这两种注入方式有各自的特点和用途。
关忆北.
2023/11/15
5700
一文告诉你Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的【享学Spring】
循环依赖:就是N个类循环(嵌套)引用。 通俗的讲就是N个Bean互相引用对方,最终形成闭环。用一副经典的图示可以表示成这样(A、B、C都代表对象,虚线代表引用关系):
YourBatman
2019/09/03
52.5K12
一文告诉你Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的【享学Spring】
Spring系列之依赖注入的方式「建议收藏」
      对于spring配置一个bean时,如果需要给该bean提供一些初始化参数,则需要通过依赖注入方式,所谓的依赖注入就是通过spring将bean所需要的一些参数传递到bean实例对象的过程,spring的依赖注入有3种方式:
Java架构师必看
2022/02/03
2.9K0
推荐阅读
相关推荐
【源码分析】Spring依赖注入原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文