首页 > 其他分享 >深入剖析循环依赖产生与解决的原理前戏

深入剖析循环依赖产生与解决的原理前戏

时间:2024-07-28 11:40:25浏览次数:9  
标签:依赖 spring class 剖析 say 循环 TestCircularBeanB TestCircularBeanA public

深入剖析循环依赖产生与解决的原理前戏

方式一:通过构造函数方式进行注入

创建两个类:

package com.coding.spring.practies;

public class TestCircularBeanA {
	private TestCircularBeanB testCircularBeanB;

	public TestCircularBeanA(TestCircularBeanB testCircularBeanB) {
		this.testCircularBeanB = testCircularBeanB;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanB.say());
	}
}
package com.coding.spring.practies;

public class TestCircularBeanB {
	private TestCircularBeanA testCircularBeanA;

	public TestCircularBeanB(TestCircularBeanA testCircularBeanA) {
		this.testCircularBeanA = testCircularBeanA;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanA.say());
	}
}

创建xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

	<!--通过构造函数注入-->
	<bean id="testCircularBeanA" class="com.coding.spring.practies.TestCircularBeanA">
		<constructor-arg ref="testCircularBeanB"></constructor-arg>
	</bean>

	<bean id="testCircularBeanB" class="com.coding.spring.practies.TestCircularBeanB">
		<constructor-arg ref="testCircularBeanA"></constructor-arg>
	</bean>

</beans>

编写测试方法:

	@Test
	public void obtainBeanByPureAnnotation4(){
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-practies.xml");
		TestCircularBeanA circularBeanA = context.getBean(TestCircularBeanA.class);
		TestCircularBeanB circularBeanB = context.getBean(TestCircularBeanB.class);
		circularBeanA.print();
		circularBeanB.print();
	}

运行结果分析:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testCircularBeanA' defined in class path resource [spring-practies.xml]: Cannot resolve reference to bean 'testCircularBeanB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testCircularBeanB' defined in class path resource [spring-practies.xml]: Cannot resolve reference to bean 'testCircularBeanA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testCircularBeanA': Requested bean is currently in creation: Is there an unresolvable circular reference? 
    
从报错信息上面我们能够看出来,是否有一个没有解决的循环引用依赖。
	

方式二:使用set方法注入

创建两个类:

package com.coding.spring.practies;

public class TestCircularBeanA {
	private TestCircularBeanB testCircularBeanB;

	public TestCircularBeanB getTestCircularBeanB() {
		return testCircularBeanB;
	}
	// 通过set方法注入
	public void setTestCircularBeanB(TestCircularBeanB testCircularBeanB) {
		this.testCircularBeanB = testCircularBeanB;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanB.say());
	}
}
package com.coding.spring.practies;

public class TestCircularBeanB {
	private TestCircularBeanA testCircularBeanA;

	public TestCircularBeanA getTestCircularBeanA() {
		return testCircularBeanA;
	}

	// 通过set方法注入
	public void setTestCircularBeanA(TestCircularBeanA testCircularBeanA) {
		this.testCircularBeanA = testCircularBeanA;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanA.say());
	}
}

创建spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

	<!--通过set方法注入-->
	<bean id="testCircularBeanA" class="com.coding.spring.practies.TestCircularBeanA">
		<property name="testCircularBeanB" ref="testCircularBeanB"></property>
	</bean>

	<bean id="testCircularBeanB" class="com.coding.spring.practies.TestCircularBeanB">
		<property name="testCircularBeanA" ref="testCircularBeanA"></property>
	</bean>

</beans>

编写测试类:

	@Test
	public void obtainBeanByPureAnnotation4(){
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-practies.xml");
		TestCircularBeanA circularBeanA = context.getBean(TestCircularBeanA.class);
		TestCircularBeanB circularBeanB = context.getBean(TestCircularBeanB.class);
		circularBeanA.print();
		circularBeanB.print();
	}

运行结果分析:

class com.coding.spring.practies.TestCircularBeanA---->class com.coding.spring.practies.TestCircularBeanB-->I am say()
class com.coding.spring.practies.TestCircularBeanB---->class com.coding.spring.practies.TestCircularBeanA-->I am say()
由此可以通过set注入的方式能够解决循环依赖的问题。

方式三:通过自动扫描的方式注入

创建两个类:

package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanA {
	private TestCircularBeanB testCircularBeanB;

	public TestCircularBeanB getTestCircularBeanB() {
		return testCircularBeanB;
	}
	// 通过set方法注入加上@Autowired注解
	@Autowired
	public void setTestCircularBeanB(TestCircularBeanB testCircularBeanB) {
		this.testCircularBeanB = testCircularBeanB;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanB.say());
	}
}
package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanB {
	private TestCircularBeanA testCircularBeanA;

	public TestCircularBeanA getTestCircularBeanA() {
		return testCircularBeanA;
	}

	// 通过set方法注入加上@Autowired注解
	@Autowired
	public void setTestCircularBeanA(TestCircularBeanA testCircularBeanA) {
		this.testCircularBeanA = testCircularBeanA;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanA.say());
	}
}

创建测试类:

	@Test
	public void obtainBeanByPureAnnotation4(){
		ApplicationContext context = new AnnotationConfigApplicationContext("com.coding.spring.practies");
		TestCircularBeanA circularBeanA = context.getBean(TestCircularBeanA.class);
		TestCircularBeanB circularBeanB = context.getBean(TestCircularBeanB.class);
		circularBeanA.print();
		circularBeanB.print();
	}

运行结果分析:

class com.coding.spring.practies.TestCircularBeanA---->class com.coding.spring.practies.TestCircularBeanB-->I am say()
class com.coding.spring.practies.TestCircularBeanB---->class com.coding.spring.practies.TestCircularBeanA-->I am say()

由此可以,使用set方式结合扫描注解能够解决循环依赖的问题

方式四:通过构造方法加注解的方式注入

创建两个类:

package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanA {
	private TestCircularBeanB testCircularBeanB;

	// 通过构造方法注入加上@Autowired注解
	@Autowired
	public TestCircularBeanA(TestCircularBeanB testCircularBeanB) {
		this.testCircularBeanB = testCircularBeanB;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanB.say());
	}
}
package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanB {
	private TestCircularBeanA testCircularBeanA;

	// 通过构造方法注入加上@Autowired注解
	@Autowired
	public TestCircularBeanB(TestCircularBeanA testCircularBeanA) {
		this.testCircularBeanA = testCircularBeanA;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanA.say());
	}
}

编写测试类:

	@Test
	public void obtainBeanByPureAnnotation4(){
		ApplicationContext context = new AnnotationConfigApplicationContext("com.coding.spring.practies");
		TestCircularBeanA circularBeanA = context.getBean(TestCircularBeanA.class);
		TestCircularBeanB circularBeanB = context.getBean(TestCircularBeanB.class);
		circularBeanA.print();
		circularBeanB.print();
	}

运行结果分析:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testCircularBeanA' defined in file [D:\ideaProject\spring-framework\coding-example\build\classes\java\main\com\coding\spring\practies\TestCircularBeanA.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testCircularBeanB' defined in file [D:\ideaProject\spring-framework\coding-example\build\classes\java\main\com\coding\spring\practies\TestCircularBeanB.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testCircularBeanA': Requested bean is currently in creation: Is there an unresolvable circular reference?
是否有一个未解决的循环依赖

由此可见,这种方式会产生循环依赖。

方式五:使用@Lazy懒加载的方式进行解决

创建两个类:

package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanA {
	private TestCircularBeanB testCircularBeanB;

	// 通过构造方法注入加上@Lazy注解
	@Autowired
	public TestCircularBeanA(TestCircularBeanB testCircularBeanB) {
		this.testCircularBeanB = testCircularBeanB;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanB.say());
	}
}
package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanB {
	private TestCircularBeanA testCircularBeanA;

	// 通过构造方法注入加上@Lazy注解
	@Autowired
	public TestCircularBeanB(@Lazy TestCircularBeanA testCircularBeanA) {
		this.testCircularBeanA = testCircularBeanA;
	}

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanA.say());
	}
}

编写测试类:

	@Test
	public void obtainBeanByPureAnnotation4(){
		ApplicationContext context = new AnnotationConfigApplicationContext("com.coding.spring.practies");
		TestCircularBeanA circularBeanA = context.getBean(TestCircularBeanA.class);
		TestCircularBeanB circularBeanB = context.getBean(TestCircularBeanB.class);
		circularBeanA.print();
		circularBeanB.print();
	}

运行结果分析:

class com.coding.spring.practies.TestCircularBeanA---->class com.coding.spring.practies.TestCircularBeanB-->I am say()
class com.coding.spring.practies.TestCircularBeanB---->class com.coding.spring.practies.TestCircularBeanA-->I am say()

由此可见,这种方式能够解决循环依赖的。其中,@Lazy注解只要加到其中一个类上就可以了。

方式六:字段属性上加@Autowired注解

创建两个类:

package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanA {
	@Autowired
	private TestCircularBeanB testCircularBeanB;

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanB.say());
	}
}
package com.coding.spring.practies;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestCircularBeanB {
	@Autowired
	private TestCircularBeanA testCircularBeanA;

	public String say(){
		return this.getClass() + "-->I am say()";
	}

	public void print(){
		System.out.println(this.getClass() + "---->" + testCircularBeanA.say());
	}
}

编写测试类:

	@Test
	public void obtainBeanByPureAnnotation4(){
		ApplicationContext context = new AnnotationConfigApplicationContext("com.coding.spring.practies");
		TestCircularBeanA circularBeanA = context.getBean(TestCircularBeanA.class);
		TestCircularBeanB circularBeanB = context.getBean(TestCircularBeanB.class);
		circularBeanA.print();
		circularBeanB.print();
	}

运行结果分析:

class com.coding.spring.practies.TestCircularBeanA---->class com.coding.spring.practies.TestCircularBeanB-->I am say()
class com.coding.spring.practies.TestCircularBeanB---->class com.coding.spring.practies.TestCircularBeanA-->I am say()

由此可见,这种方式是能够解决循环依赖的。

其中

	@Autowired
	private TestCircularBeanA testCircularBeanA;

等同于:

	@Autowired
	public void setTestCircularBeanA(TestCircularBeanA testCircularBeanA) {
		this.testCircularBeanA = testCircularBeanA;
	}

标签:依赖,spring,class,剖析,say,循环,TestCircularBeanB,TestCircularBeanA,public
From: https://www.cnblogs.com/dongyaotou/p/18328015

相关文章

  • ECCV 2024|是真看到了,还是以为自己看到了?多模态大模型对文本预训练知识的过度依赖该解
    随着大型语言模型(LLMs)的进步,多模态大型语言模型(MLLMs)迅速发展。它们使用预训练的视觉编码器处理图像,并将图像与文本信息一同作为Token嵌入输入至LLMs,从而扩展了模型处理图像输入的对话能力。这种能力的提升为自动驾驶和医疗助手等多种潜在应用领域带来了可能性。点击访问......
  • python中的while循环不退出
    我试图完成第一年的python商业课程作业,但我的while循环无法退出,有人能帮忙吗?commisionTable=[{"admin_fee":100,"comm_rate":0.10},{"admin_fee":125,"comm_rate":0.12},{"admin_fee":150,"comm_rate":......
  • 基础循环+识图
    /*按下指定按键执行操作*/Dokey=WaitKey()/*F2*/Ifkey=113ThenKeyDown"Ctrl",1Delay30KeyPress"C",1Delay30KeyUp"Ctrl",1Delay30/*F4*/ElseI......
  • Temperatures()函数中用const创建温度转换中使用的变量.在main()函数中使用一个循环让
    /编写一个程序,要求用户输入一个华氏温度。程序应读取double类型的值作为温度值,并把该值作为参数传递该一个用户自定义的函数Temperatures()。该函数计算摄氏温度和开氏温度,并以小数点后面两位数字的精度显示3种温度。要求使用不同的温度标签来表示这3个温度值。下面是华氏温度转......
  • Windows下用CMake构建和编译第三方依赖库并向C:\Program Files\或C:\Program Files
    从CMake构建和编译第三方依赖库的步骤:1、下载第三方依赖库的源码,并解压到指定的目录中。2、在第三方依赖库的的源码所在的目录下(一般是src/目录下)创建一个文件夹build。3、打开CMakeGUI软件,按照常规步骤配置和产生针对某种编译器的解决方案文件,比如Visualstudio2019。如下如......
  • Linux: 更新系统相关依赖命令yum update执行失败: One of the configured repositorie
    环境:CentOS7(ISO映像文件=CentOS-7-x86_64-DVD-2009.iso)解决思路:系统repo镜像源连接问题导致执行失败,切换repo为国内源即可#切换仓库镜像源curl-o/etc/yum.repos.d/CentOS-Base.repohttps://mirrors.aliyun.com/repo/Centos-7.repo#或者wget-O/etc/yum.rep......
  • 属性填充底层源码深入剖析前戏
    属性填充底层源码深入剖析前戏方式一:使用set方式注入创建两个类:packagecom.coding.spring.practies;publicclassTestDIBean{ publicStringsay(){ return"IamTestDIBean.say()"; }}packagecom.coding.spring.practies;publicclassTestDIBean2{ priva......
  • 有参构造函数注入底层源码深入剖析**前戏
    有参构造函数注入底层源码深入剖析前戏方式一:创建两个类:publicclassTestDIBean{ publicStringsay(){ return"IamTestDIBean.say()"; }}packagecom.coding.spring.practies;publicclassTestDIBean1{ privateTestDIBeantestDIBean; publicTestDIBean......
  • 5 用户输入和while循环
    5.1函数input()工作原理#变量=input(参数:说明/提示)messageinput("Tellmesomething,andIwillrepeatitbacktoyou:"print(message)prompt="Ifyoutelluswhoyouare,wecanpersonalizethemessagesyousee."#prompt=prompt+"\nWhatisy......
  • idea在pom中引入第三方依赖
    项目右侧点击maven,点击加号(鼠标放上去会出现addmavenproject字样) 找到要导入的项目的pom文件选中,ok(这里我以及导入过了,所以ok是灰色) 回到原项目中,在pom中添加dependency其中,artifactId是导入进来的姓名的名字,groupId是导入进来的项目的java目录下的包名 ......