白话理解什么是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小兄弟,闻道有先后,从他写的和整理的材料里理顺了不少思路

posted on 2021-11-25 17:08  肥兔子爱豆畜子  阅读(133)  评论(0编辑  收藏  举报

导航