Spring循环依赖原理分析
Posted 赵晓东-Nastu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring循环依赖原理分析相关的知识,希望对你有一定的参考价值。
一、思维导图
二、什么是循环依赖
从这个图中可以看出,当有2个对象互相依赖的时候,在创建的时候会存在一个环形的调用,导致创建对象失败。
所以:循环依赖是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了一个环形调用。
三、如何解决循环依赖
通过三级缓存来解决循环依赖的问题
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
具体的步骤是什么样子的?
首先走Refresh()方法,开始实例化
//初始化剩下的单实例(从这里开始进行实例化了)
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
将这个方法走进去就进入到了下面
//实例化剩下的所有的非懒加载的单例对象
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
通过beanName获取
//如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例
getBean(beanName);
@Override
public Object getBean(String name) throws BeansException {
//此方法是实际获取bean的方法,也是触发依赖注入的方法
return doGetBean(name, null, null, false);
}
接下来我需要判断,获取对象,从容器里面获取,容器里面保存了三级缓存
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
//接下来就是获取bean的对象
// 尝试通过bean名称获取目标bean对象,比如这里的A对象
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
接下来我们走到getSingleton方法中
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//尝试从缓存中获取成品的目标对象,如果存在,则直接返回
Object singletonObject = this.singletonObjects.get(beanName);
//如果缓存中不存在目标对象,则判断当前对象是否已经处于创建过程中,
//第一次尝试获取A对象的实例之后,就会将A对象标记为正在创建中,因而最后再尝试获取A对象的时候这里的if就会为true
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//这里的singletonFactories是一个map ,其key是bean的名称,而值是一个ObjectFactory类型的
//对象,这里对于A和B而言,调用getObject()方法返回的就是A和B对象的实例,无论是否是半成品
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//获取目标对象的实例
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
刚开始的时候,if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 这个判断是false,所以直接返回的是null。
因为还没有被创建,所以返回空值,容器里面没有,所以接下来就是去创建了。
//这里的目标对象都是单例的
// Create bean instance.
if (mbd.isSingleton()) {
//这里就尝试创建目标对象。第二个参数传的就是一个ObjectFactory类型的对象,这里是
//使用Java8的lamada表达式写的,只要上面的getSingleton()方法返回值为空,则会调用这里的
//getSingleton方法
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
接下来我们走进getSingleton方法,从singletonFactory.getObject()获取对象,这个也就是传进来的lambda表达式createBean()
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) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//从单例工厂中获取对象
singletonObject = singletonFactory.getObject();
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
//实例化当前获取的bean对象,比如A对象和B对象都是在这里实例化的
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//没有就创建实例
if (instanceWrapper == null) {
//根据执行bean使用对应的策略创建新的实例,如:工厂方法,构造函数主动注入,简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
所以从现在开始就开始进行对象的实例化操作了,然后走到createBeanInstance方法,创建实例。
此时完成了半成品,实例化结束了,接下来就是填充属性了。
//如果支持,这里就会将当前生产的半成品的bean放到singletonFactories中,
//这个singletonFactories 就是前面第一个getSingleton()方法中所使用的singletonFactories属性,也就是说
//这里就是封装半成品的bean的地方,而这里的getEarlyBeanReference()本质上
//是直接将放入的第三个参数,也就是目标bean直接返回
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
//使用singletonObjects进行加锁,保证线程安全
synchronized (this.singletonObjects) {
//如果单例对象的告诉缓存【bean名称-bean实例】没有beanName对象
if (!this.singletonObjects.containsKey(beanName)) {
//将beanName , singletonFactory放到单例工厂的缓存[bean名称-objectFactory]
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
//将beanName添加已注册的单例集中
this.registeredSingletons.add(beanName);
}
}
}
从源代码中可以看出,spring将创建好的对象实例化放入到了singletonFactories中
接下来填充属性
//在初始化实例之后,这里就是判断当前bean是否依赖了其他的bean,如果依赖了
//就会递归的调用getBean()方法尝试获取目标bean
populateBean(beanName, mbd, instanceWrapper);
走进去
if (pvs != null) {
//应用给定的属性值,解决任何在这个bean工厂运行时其他bean的引用
applyPropertyValues(beanName, mbd, bw, pvs);
}
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
然后到valueResolver.resolveValueIfNecessary(pv, originalValue);
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
点击进resolveReference
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
bean = this.beanFactory.getBean(refName);
走到
bean = this.beanFactory.getBean(refName);
接下来又就到了
@Override
public Object getBean(String name) throws BeansException {
//此方法是实际获取bean的方法,也是触发依赖注入的方法
return doGetBean(name, null, null, false);
}
开始递归循环。。。。然后都创建完实例并且存放到singletonFactories中,然后现在执行populateBean装配属性,然后userService,发现有一个属性是IndexService。
因此再次调用doGetBean创建userService实例,但是执行到getSingleton查询缓存的时候,从SingletonFactories三级缓存中查询到了userService实例(早起引用,未完成属性装配),此时直接返回userService,不用执行后续的流程创建userService了,那么IndexService就完成了属性装配,此时是一个完成的对象放入到了一级缓存singletonObjects中,
IndexService创建完了,则userService自然完成了属性装配,也创建完成放入一级缓存singletonObjects中
Spring三级缓存的应用完美解决了循环依赖的问题。
总结成图片:
以上是关于Spring循环依赖原理分析的主要内容,如果未能解决你的问题,请参考以下文章