spring怎么避免循环依赖

1、循环依赖

(1)概念

对象依赖分为强依赖和弱依赖:

强依赖指的是一个对象包含了另外一个对象的引用,例如:学生类中包含了课程类,在学生类中存在课程类的引用

创建课程类:

@Data
public class Course {
private String cname;
private Integer credit;
}

创建学生类:

@Data
public class Student {
private String sname;
private int age;
private Course course;
}

测试类:

public class Test {
public static void main(String[] args) {
Student student=new Student();
Course course=new Course();
student.setCourse(course);
}
}

弱依赖指的是一个对象里面调用了另外一个对象

循环依赖:A引用B,而B又引用A

创建课程类,课程类中有学生类的引用:

@Data
public class Course {
private String cname;
private Integer credit;
private Student student;
}

创建学生类,学生类中存在课程类中的引用:

@Data
public class Student {
private String sname;
private int age;
private Course course;
}

创建测试类,测试类中学生类调用课程类的对象,课程类的对象又调用学生类的对象:

public class Test {
public static void main(String[] args) {
Student student=new Student();
Course course=new Course();
student.setCourse(course);
course.setStudent(student);
}
}

测试类可以正常地获取对象,也就是说这种方式是支持循环依赖的。

(2)spring的循环依赖

    <bean id="student" class="com.zhb.bean.Student" scope="singleton">
<property name="course" ref="course"></property>
</bean>
<bean id="course" class="com.zhb.bean.Course" scope="singleton">
<property name="student" ref="student"></property>
</bean>

单例模式下支持,多例模式下不支持

(3)spring是否支持循环依赖

支持

(4)spring的所有对象是不是都支持循环依赖

单例模式下支持:单例模式下是首先创建出两个对象,然后进行依赖的注入。A注入B,B注入A。

多例模式下不支持:A创建的时候会去判断是否依赖于其他对象,如果依赖的话就不会去先创建A。创建B的时候也会去判断是否依赖其他对象,如果A依赖于B,而B又依赖于A的话就会造成一个死循环,两个对象都不会创建。

2、spring循环依赖的过程

(1)流程

spring怎么避免循环依赖

(2)源码

ClassPathXmlApplicationContext方法:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();//refresh方法是真正的创建对象的方法
} }

refresh方法:

public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory); try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);//Bean工厂的后置处理器
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);//此方法是真正的创建对象的方法,能够实例化所有的单例bean
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
} this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
} }
}

finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
} if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver((strVal) -> {
return this.getEnvironment().resolvePlaceholders(strVal);
});
} String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
String[] var3 = weaverAwareNames;
int var4 = weaverAwareNames.length; for(int var5 = 0; var5 < var4; ++var5) {
String weaverAwareName = var3[var5];
this.getBean(weaverAwareName);
} beanFactory.setTempClassLoader((ClassLoader)null);
beanFactory.freezeConfiguration();
beanFactory.preInstantiateSingletons();
}

接口:

void preInstantiateSingletons() throws BeansException;
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Pre-instantiating singletons in " + this);
} List<String> beanNames = new ArrayList(this.beanDefinitionNames);
Iterator var2 = beanNames.iterator();//取出名字 while(true) {
String beanName;
Object bean;
do {
while(true) {
RootBeanDefinition bd;
do {
do {
do {
if (!var2.hasNext()) {
var2 = beanNames.iterator(); while(var2.hasNext()) {
beanName = (String)var2.next();
Object singletonInstance = this.getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
} return;
} beanName = (String)var2.next();
bd = this.getMergedLocalBeanDefinition(beanName);
} while(bd.isAbstract());//单例抽象懒加载
} while(!bd.isSingleton());
} while(bd.isLazyInit()); if (this.isFactoryBean(beanName)) {
bean = this.getBean("&" + beanName);
break;
} this.getBean(beanName);
}
} while(!(bean instanceof FactoryBean)); FactoryBean<?> factory = (FactoryBean)bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
SmartFactoryBean var10000 = (SmartFactoryBean)factory;
((SmartFactoryBean)factory).getClass();
isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());
} else {
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
} if (isEagerInit) {
this.getBean(beanName);
}
}
}

getSingleton方法:

 @Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);//
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
} return singletonObject;
}

3、怎么避免循环依赖?

三级缓存

  • 一级缓存:singletonObjects,存放完全实例化属性赋值完成的Bean,直接可以使用。
  • 二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean
  • 三级缓存:singletonFactories,三级缓存,存放实例化完成的Bean工厂。

假设A依赖B,B依赖A(注意:这里是set属性依赖)分以下步骤执行:

  A依次执行doGetBean、查询缓存、createBean创建实例,实例化完成放入三级缓存singletonFactories中,接着执行populateBean方法装配属性,但是发现有一个属性是B的对象。因此再次调用doGetBean方法创建B的实例,依次执行doGetBean、查询缓存、createBean创建实例,实例化完成之后放入三级缓存singletonFactories中,执行populateBean装配属性,但是此时发现有一个属性是A对象。

  因此再次调用doGetBean创建A的实例,但是执行到getSingleton查询缓存的时候,从三级缓存中查询到了A的实例(早期引用,未完成属性装配),此时直接返回A,不用执行后续的流程创建A了,那么B就完成了属性装配,此时是一个完整的对象放入到一级缓存singletonObjects中。

  B创建完成了,则A自然完成了属性装配,也创建完成放入了一级缓存singletonObjects中。

上一篇:Spring 如何解决循环依赖的问题


下一篇:面试阿里,腾讯,字节跳动90%都会被问到的Spring中的循环依赖