Spring如何解决循环依赖?
spring是怎么解决循环依赖的,一级、二级、三级缓存扮演什么角色?
本次分享,包括
1.一个简单的单例Bean的实例化过程
2.存在依赖的单例Bean的实例化过程
3.存在循环依赖的单例Bean的实例化过程
一个简单的单例Bean的实例化过程
定义一个SimpleBean
package com.mytest.spring;
import org.springframework.stereotype.Component;
public class SimpleBean {
public SimpleBean() {
System.out.println("SimpleBean 创建了");
}
public void say() {
System.out.println("SimpleBean say");
}
}
定义一个测试类MySpringTest
package com.mytest.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MySpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(SimpleBean.class);
annotationConfigApplicationContext.refresh();
}
}
annotationConfigApplicationContext.refresh()会调finishBeanFactoryInitialization(beanFactory),该方法会完成单例bean的实例化。
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
SimpleBean实例化过程图:
因没有属性依赖流程比较简单,
创建的单例bean会存在一级缓存,再次获取bean时直接从一级缓存中获取。接着我们来看存在依赖的Bean实例化过程。
存在依赖的单例Bean的实例化过程
定义一个带@Autowired的类HasAutowiredBean
package com.mytest.spring;
import org.springframework.beans.factory.annotation.Autowired;
public class HasAutowiredBean {
@Autowired
private SimpleBean simpleBean;
public HasAutowiredBean() {
System.out.println("HasAutowiredBean 创建了");
}
public void say() {
System.out.println("HasAutowiredBean say");
}
}
测试类MySpringTest中注册HasAutowiredBean.class
package com.mytest.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MySpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(SimpleBean.class);
annotationConfigApplicationContext.register(HasAutowiredBean.class);
annotationConfigApplicationContext.refresh();
}
}
实例化过程如图:
过程也很简单,先实例化Bean:hasAutowiredBean,再根据@Autowired实例化Bean:simpleBean。
实例化完成都将放入一级缓存中。
存在循环依赖的单例Bean的实例化过程
定义一个类CircleAutowiredBeanA,其中依赖了CircleAutowiredBeanB
package com.mytest.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CircleAutowiredBeanA {
@Autowired
private CircleAutowiredBeanB circleAutowiredBeanB;
public CircleAutowiredBeanA() {
System.out.println("CircleAutowiredBeanA 创建了");
}
public void say() {
System.out.println("CircleAutowiredBeanA say");
}
}
再定义一个类CircleAutowiredBeanB,其中依赖了CircleAutowiredBeanA
package com.mytest.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CircleAutowiredBeanB {
@Autowired
private CircleAutowiredBeanA circleAutowiredBeanA;
public CircleAutowiredBeanB() {
System.out.println("CircleAutowiredBeanB 创建了");
}
public void say() {
System.out.println("CircleAutowiredBeanB say");
}
}
类的关系如图:
修改测试类MySpringTest
package com.mytest.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MySpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(CircleAutowiredBeanA.class);
annotationConfigApplicationContext.register(CircleAutowiredBeanB.class);
annotationConfigApplicationContext.refresh();
}
}
执行完,输出:
CircleAutowiredBeanA 创建了
CircleAutowiredBeanB 创建了
实例化过程图:
为解决循环依赖,流程有点复杂,大概步骤:
1)首先加载Bean:circleAutowiredBeanA,实例化一个对象,记录circleAutowiredBeanA的三级缓存
2)给circleAutowiredBeanA的属性circleAutowiredBeanB赋值,加载Bean:circleAutowiredBeanB,实例化一个对象
3)给circleAutowiredBeanB的属性circleAutowiredBeanA赋值,从三级缓存中获取到circleAutowiredBeanA对象(此时的circleAutowiredBeanA,可能会由先前加入到三级缓存中的函数接口创建一个代理对象),加入到二级缓存;然后给属性circleAutowiredBeanA赋值。
4)circleAutowiredBeanB对象赋值完成,初始化,然后加入到一级缓存,并返回给circleAutowiredBeanA。
5)加载完circleAutowiredBeanB,回到circleAutowiredBeanA。获取二级缓存的circleAutowiredBeanA对象,添加到一级缓存。
到此,Spring循环依赖分享完毕,有问题欢迎指正。