目录
百战程序员,全站22050+开发课程+文档 ,学习精选优质好课快人一步!观看视频 快捷键ALT+N

JAVA全系列 教程

3762个小节阅读:7092.7k

收藏
全部开发者教程

C语言快速入门

JAVA全系列 教程

面向对象的程序设计语言

Python全系列 教程

Python3.x版本,未来主流的版本

人工智能 教程

顺势而为,AI创新未来

大厂算法 教程

算法,程序员自我提升必经之路

C++ 教程

一门通用计算机编程语言

微服务 教程

目前业界流行的框架组合

web前端全系列 教程

通向WEB技术世界的钥匙

大数据全系列 教程

站在云端操控万千数据

AIGC全能工具班

A

A A

White Night

阅读(502)
赞(0)

十七、Spring 循环注入问题

我们前面学习了DI的两种方式,分别是构造注入和设值注入。这两种方式,官方更推荐使用构造注入。

网址:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-setter-injection

image-20230322135331111

但是有一种情况确实无法使用构造注入,就是循环依赖的问题。

循环依赖就是多个Bean相互依赖,形成一个闭环。

xunhuanyinyong

下面我们先看看Spring 官方中对构造注入时出现循环注入的解释。

当两个类都是用构造注入时,没有等当前类实例化完成就需要注入另一个类,而另一个类没有实例化完整还需要注入当前类,所以这种情况是无法解决循环注入问题的的。会出现BeanCurrentlyInCreationException异常。

image-20230322135429567

其实Spring循环注入问题并不是我们开发者去解决的,而是Spring本身会根据我们的代码进行解决。其中有的情况能解决,有的会直接报异常。汇总如下:

  • 第一种:两个Bean都是用构造注入时,且scope为singleton是有循环注入异常的。
  • 第二种:两个Bean都是用构造注入时,且scope为prototype是有循环注入异常的。
  • 第三种:如果Bean的scope属性为prototype时,使用设值注入是有循环注入异常的。
  • 第四种:如果Bean的scope属性都为singleton时,使用设值注入Spring没有循环注入异常。
  • 第五种:如果一个Bean的scope为singleton,另一个Bean的scope为prototype,都使用设置注入时没有循环注入异常。
  • 第六种:如果一个Bean使用设值注入,且scope为singleton,另一个Bean使用构造注入,是没有循环注入异常的。

通过这六种情况可以看出来,只要一个Bean使用设值注入,并且scope为singleton,就没有循环注入异常。

下面通过代码给小伙伴们演示一下构造注入时循环注入的效果。

在搭建好Spring环境的项目中新建两个类:

先新建com.bjsxt.circular.Teacher类代表老师

然后在新建个com.bjsxt.circular.Student类,代表学生

在Spring的配置文件applicationContext.xml中设置两个Bean的循环注入

最后在测试类com.bjsxt.test.CircularTest中编写测试代码

运行测试类后会发现IDEA控制台出现异常。最后一个Cased by的异常类型是Caused by: org.springframework.beans.factory.BeanCreationException,代表着发生了循环注入问题。

这种方式可以理解,因为在Java代码中下面代码就编译错误了。

第二种情况,两个Bean的scope都是prototype类型,依然使用构造注入。运行后依然出现BeanCurrentlyInCreationException

第三种情况,使用设值注入。如果Bean的scope属性为prototype时,循环注入的效果。

我们先把配置修改一下,注入的方式修改为设置注入,并设置Bean的scope="prototype"

运行测试类,发现依然会产生循环注入问题。控制台还是出现了BeanCurrentlyInCreationException异常。

第四种情况,使用设值注入。Bean的scope属性为singleton时,循环注入的效果。

只需要修改配置文件中,把<bean>的scope属性设置为singleton就可以了。

运行后没有循环注入异常了,但是出现StackOverflowError.是因为@Data生成的toString()中循环包含对方对象。

修改两个类的,在关联属性都添加上不被toString()输出。

再次运行,程序可以正常输出。

这种方式之所以可以成功运行是因为单例默认下有三级缓存(DefaultSingletonBeanRegistry),可以暂时缓存没有被实例化完成的Bean。这样就不用考虑Bean实例化时先后问题,也就不会出现循环注入问题了。

第四种情况,使用设值注入。一个类scope="singleton",另外一个类scope="prototype"。

这时发现,两个类都可以被成功注入。

第五种情况,一个类使用构造注入,另一个类使用设置注入并且scope="singleton"

通过这些演示后小伙伴们知道了只要Bean的scope="singleton"就不会出现循环注入问题。那么在平时我们进行代码编写时,尽量避开循环注入。如果实在无法避开,类中涉及到两个类的相互引用。例如:双向多对一、双向一对一的关系中就必须有双向引用。这时最好使用设值注入,并且scope设置为singleton。

 

北京市昌平区回龙观镇南店村综合商业楼2楼226室

©2014-2023 百战卓越(北京)科技有限公司 All Rights Reserved.

京ICP备14032124号-2