白话理解什么是Spring循环依赖
我们知道Spring IOC是指的容器来负责创建Bean并负责处理Bean之间的依赖关系,比如有如下两个类A、B:
@Component
public class A
@Autowired
private B b;
@Component
public class B
站在容器的角度,发现A依赖B,直接先创建B然后创建A,把B实例赋值给A的成员变量b,完事儿。
但如果是下面一种循环依赖的情况,按照上面的逻辑就不可行了:
循环依赖
@Component
public class A
@Autowired
private B b;
@Component
public class B
@Autowired
private C c;
@Component
public class C
@Autowired
private A a;
A依赖B、B依赖C、C又依赖A
如果你是容器,尼玛到底该先创建谁??
解决思路
创建一个类实例之前,先去一个全局的缓存Map里看下是否有这个类的实例,如果有则说明已经创建过、直接返回,如果没有则创建。
创建类实例的对应的属性的实例、并赋值给成员变量。递归。
创建A的实例,加入缓存Map,遍历A的属性,发现B需要创建,创建B的实例也加入缓存,遍历B的属性发现需要创建C,创建C的实例,遍历C的属性发现需要创建A的实例,但是A实例已经在缓存了、直接赋值。循环结束。
下面按照上面的思路,写下代码模拟循环依赖的解决:
package com.wangan.cyclicdependency;
public class A {
public B b;
}
public class B {
public C c;
}
public class C {
public A a;
}
package com.wangan.cyclicdependency;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* 模拟简单循环依赖解决
* */
public class TestCyclicDependency {
private static Map<String, Object> beanCache = new HashMap<>();
public static void main(String[] args) throws Exception {
String[] beanDefinations = {"com.wangan.cyclicdependency.A",
"com.wangan.cyclicdependency.B",
"com.wangan.cyclicdependency.C"};
for(String beanName : beanDefinations) {
getBean(beanName);
}
A a = (A) beanCache.get("com.wangan.cyclicdependency.A");
B b = (B) beanCache.get("com.wangan.cyclicdependency.B");
C c = (C) beanCache.get("com.wangan.cyclicdependency.C");
System.out.println(a.b);
System.out.println(b.c);
System.out.println(c.a);
System.out.println(a.b==b);
System.out.println(b.c==c);
System.out.println(c.a==a);
}
public static Object getBean(String beanName) throws Exception {
if(beanCache.containsKey(beanName)) {
return beanCache.get(beanName);
}else {
Object bean = Class.forName(beanName).newInstance();
beanCache.put(beanName, bean);
Field[] fields = bean.getClass().getFields();
for(Field f : fields) {
String typeClassName = f.getType().getName();
f.setAccessible(true);
f.set(bean, getBean(typeClassName));
}
return bean;
}
}
}
Spring中的循环依赖问题
先对于我们上面的简单例子,Spring要面对的问题要复杂一些,即要实现AOP,相对于我们上面使用了1个Map来作为缓存来暂存Bean,Spring使用了3个Map形成所谓的“三级缓存”。
DefaultSingletonBeanRegistry.java,继承关系是DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory extends AbstractBeanFactory extends FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry (吐槽一下,所以说Spring的源代码为什么难读,瞅瞅这继承的关系有多深)
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
singletonObjects
是1级缓存,就是所谓的单例池,存放经过代理的且经过初始化的完整的Bean。earlySingletonObjects
是2级缓存,存放实例化之后、且经过代理的Bean,但是还没有初始化(也就是属性还没填充)。singletonFactories
是3级缓存,存放用实例化后的Bean对象封装成的工厂对象,如果有AOP则这个工厂对象getObject直接返回原实例化对象、如果启用了AOP那么这个工厂对象返回的就是加了AOP切面的动态代理对象。
下面我们还是用代码模拟一下,以加深理解:
互相依赖的两个类,A和B:
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Data
public class A {
@Autowired
private B b;
public A() {
log.info("A初始化");
}
public void helloA() {
log.info("hello A");
}
}
@Slf4j
@Data
public class B {
@Autowired
private A a;
public B() {
log.info("B初始化");
}
public void helloB() {
log.info("hello B");
}
}
DefaultSingletonBeanRegistry
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.util.Assert;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DefaultSingletonBeanRegistry {
//1级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//2级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//3级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
this.singletonsCurrentlyInCreation.add(beanName);
boolean newSingleton = false;
singletonObject = singletonFactory.getObject();
newSingleton = true;
this.singletonsCurrentlyInCreation.remove(beanName);
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
//this.registeredSingletons.add(beanName);
}
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
//this.registeredSingletons.add(beanName);
}
}
}
protected void removeSingleton(String beanName) {
synchronized (this.singletonObjects) {
this.singletonObjects.remove(beanName);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
//this.registeredSingletons.remove(beanName);
}
}
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
}
BeanFactory,继承BeanRegistry:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.RootBeanDefinition;
public class DefaultListenableBeanFactory extends DefaultSingletonBeanRegistry{
private final Map<String, RootBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public void registerBeanDefinition(String beanName, RootBeanDefinition beanDefinition) {
this.beanDefinitionMap.put(beanName, beanDefinition);
}
public Object getBean(String beanName) {
return doGetBean(beanName);
}
private Object doGetBean(String beanName) {
Object bean;
Object sharedInstance = getSingleton (beanName, true);
if(sharedInstance != null) {
return sharedInstance;
}else {
RootBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
bean = getSingleton(beanName, () -> {
return doCreateBean(beanName, beanDefinition);
});
}
return bean;
}
//创建Bean
private Object doCreateBean(String beanName, RootBeanDefinition beanDefinition) {
Object bean = createBeanInstance(beanName, beanDefinition);
//如果beanName正在创建中,而本次doCreateBean又创建,说明出现了循环依赖现象,则把它放入3级缓存里
boolean earlySingletonExposure = this.isSingletonCurrentlyInCreation(beanName);
if(earlySingletonExposure) {
this.addSingletonFactory(beanName, ()->bean);
}
Object exposedObject = bean;
//属性赋值
populateBean(beanName, beanDefinition, bean);
if(earlySingletonExposure) {
Object earlySingletonReference = getSingleton (beanName, false);
if(earlySingletonReference != null)
exposedObject = earlySingletonReference;
}
return exposedObject;
}
//实例化
private Object createBeanInstance(String beanName, RootBeanDefinition beanDefinition) {
Constructor<Object> constructor;
try {
constructor = (Constructor<Object>) beanDefinition.getBeanClass().getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//属性填充
private void populateBean(String beanName, RootBeanDefinition beanDefinition, Object beanInstance) {
Field[] fields = beanDefinition.getBeanClass().getDeclaredFields();
Arrays.stream(fields).forEach(field -> {
Autowired autowired = field.getAnnotation(Autowired.class);
if(null != autowired) {
Object beanField = this.getBean(field.getName());
field.setAccessible(true);
try {
field.set(beanInstance, beanField);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
});
}
}
测试:
public class CyclicDependencyTest {
public static void main(String[] args) {
RootBeanDefinition beanDefinitionA = new RootBeanDefinition();
beanDefinitionA.setBeanClass(A.class);
RootBeanDefinition beanDefinitionB = new RootBeanDefinition();
beanDefinitionB.setBeanClass(B.class);
DefaultListenableBeanFactory beanFactory = new DefaultListenableBeanFactory();
beanFactory.registerBeanDefinition("a", beanDefinitionA);
beanFactory.registerBeanDefinition("b", beanDefinitionB);
A a = (A) beanFactory.getBean("a");
a.getB().helloB();
B b = (B) beanFactory.getBean("b");
b.getA().helloA();
}
}
输出:
[2021-11-28 12:09:32] [ INFO ] [main] [codeline:16] - A初始化
[2021-11-28 12:09:32] [ INFO ] [main] [codeline:16] - B初始化
[2021-11-28 12:09:32] [ INFO ] [main] [codeline:20] - hello B
[2021-11-28 12:09:32] [ INFO ] [main] [codeline:20] - hello A
参考
https://mp.weixin.qq.com/s/kS0K5P4FdF3v-fiIjGIvvQ 感谢这个aobing小兄弟,闻道有先后,从他写的和整理的材料里理顺了不少思路