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

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

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

创建两个类:

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;
	}

posted on 2024-07-28 11:33  ~码铃薯~  阅读(5)  评论(0编辑  收藏  举报

导航