Spring三级缓存处理循环依赖源码解读

本文详细介绍了Spring框架中如何利用三级缓存解决循环依赖问题。通过创建User和Order类的相互引用实例,展示了在Spring配置文件中如何定义这种关系,并通过main方法启动应用验证了循环依赖可以正常处理。接着,深入源码,分析了从一级缓存到三级缓存的过程,包括Bean对象在不同缓存中的存储逻辑,以及如何通过三级缓存解决循环依赖。最后,通过图示说明了三级缓存的工作原理。
摘要由CSDN通过智能技术生成

        上一篇文章进行了spring三级缓存在源码中使用的简要概括,因为没有实际类的举例,阅读起来有点绕。本篇博客是我自己在阅读spring源码过程中,对三级缓存是如何处理循环依赖问题的细节理解。一方面希望对你有所帮助,另一方面也是对自己阅读源码的一个完整的总结过程。话不多说,进入正题。

1. 准备工作

        准备工作比较简单,准备两个类,然后类中相互引入作为对方的属性,在spring配置文件中注入,然后通过ClassPathXmlApplicationContext读取spring的配置文件。对应的源码如下:

1.1 创建两个类,User和Order

public class User {

    private Order order;

    public User() {
        System.out.println("User无参构造,通过我创建对象了");
    }

    public User(Order order) {
        this.order = order;
        System.out.println("User全参构造,通过我创建对象了");
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }
}
public class Order {

    private User user;

    public Order() {
        System.out.println("Order类使用了无参构造函数,Order被创建了");
    }

    public Order(User user) {
        this.user = user;
        System.out.println("Order类使用了全参构造函数,Order被创建了");
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

1.2 spring配置文件applicationContext.xml中配置引用关系

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置User-->
    <bean class="com.edu.spring.study.User" id="user">
        <property name="order" ref="order"/>
    </bean>

    <!--配置Order-->
    <bean class="com.edu.spring.study.Order" id="order">
        <property name="user" ref="user"/>
    </bean>
</beans>

1.3 创建main方法,读取spring配置文件

package com.edu.spring.study;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringStudyApplication {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

准备工作有想这些就可以了,User和Order类相互引用,属于循环依赖,首先看下这样的相互引用能不能正常启动,执行main方法,得到如下效果:

可以看到没有报错,正常获取到bean对象,但是怎么处理这种情况?让相互依赖的两个类都正常创建,这是我们需要探究的问题。这里面其实就是使用了三级缓存来处理了。之前的文章对bean的创建过程有过梳理,这里就不再说明了。本文主要探索的是三级缓存在源码中的使用的探究。

2. Bean对象保存到一级缓存

        当我们阅读到getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法时,可以看到,对于一个已经创建好的对象,会将对象存入一级缓存中,存入一级缓存的逻辑在addSingleton()方法中,对于的源码如下:

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 (this.logger.isDebugEnabled()) {
				this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
			}

			this.beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = this.suppressedExceptions == null;
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet();
			}

			try {
				//得到一个bean对象
				singletonObject = singletonFactory.getObject();
				//将创建完成标识标记为true
				newSingleton = true;
			} catch (IllegalStateException var16) {
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					throw var16;
				}
			} catch (BeanCreationException var17) {
				BeanCreationException ex = var17;
				if (recordSuppressedExceptions) {
					Iterator var8 = this.suppressedExceptions.iterator();

					while(var8.hasNext()) {
						Exception suppressedException = (Exception)var8.next();
						ex.addRelatedCause(suppressedException);
					}
				}

				throw ex;
			} finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}

				this.afterSingletonCreation(beanName);
			}
			//标记为已创建的对象,调用addSingleton()方法
			if (newSingleton) {
				this.addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

继续查看addSingleton()的源码,源码如下:

protected void addSingleton(String beanName, Object singletonObject) {
	synchronized(this.singletonObjects) {
		//将创建完成的bean存放到一级缓存singletonObjects中
		this.singletonObjects.put(beanName, singletonObject);
		
		//删除三级缓存中对应的bean信息
		this.singletonFactories.remove(beanName);
		
		//删除二级缓存中对应的bean信息
		this.earlySingletonObjects.remove(beanName);
		
		//将beanName存放到已创建bean的Set集合中
		this.registeredSingletons.add(beanName);
	}
}

3. Bean对象保存到二级缓存

        对象保存二级缓存的逻辑在doGetBean方法中调用getSingleton(beanName)方法中实现的,跟踪源码最终的实现逻辑在getSingleton(String beanName, boolean allowEarlyReference)中,源码如下:

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	
	//在一级缓存中查询bean对象
	Object singletonObject = this.singletonObjects.get(beanName);
	
	//判断bean是否为空,如果为空,校验bean是否正在创建中
	if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
		
		//如果一级缓存中没有并且bean正在创建中,就在二级缓存中再次查询
		singletonObject = this.earlySingletonObjects.get(beanName);
		
		//二级缓存中如果查询不到的话,对一级缓存加锁
		if (singletonObject == null && allowEarlyReference) {
			synchronized(this.singletonObjects) {
				
				//再次查询一级缓存
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					
					//一级缓存中如果bean不存在,查询二级缓存
					singletonObject = this.earlySingletonObjects.get(beanName);
					if (singletonObject == null) {
						
						//二级缓存中查询不到的话,查询三级缓存
						ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
						if (singletonFactory != null) {
							
							//三级缓存中查询到的话,执行ObjectFactory的getObject()方法,该方法执行会调用createBean方法创建对象
							singletonObject = singletonFactory.getObject();
							
							//将创建的对象保存到二级缓存earlySingletonObjects的Map集合中
							this.earlySingletonObjects.put(beanName, singletonObject);
							
							//删除三级缓存中对应的bean信息
							this.singletonFactories.remove(beanName);
						}
					}
				}
			}
		}
	}
	
	//返回获取的bean
	return singletonObject;
}

源码中可以看到,getSingleton()方法中会将bean信息存入二级缓存中。将bean对象放入二级缓存,就必须在三级缓存中存在bean信息,才可以得到bean对象,而三级缓存中存放的是以beanName作为key,ObjectFactory接口的实现类最为value的信息。那么接下来就需要找到三级缓存存放的位置。

4. Bean对象保存到三级缓存

        前面我们已经看到了一级缓存和二级缓存的使用源码了,就是还没看到三级缓存的相关运用源码。接下来我们来探究三级缓存的源码,三级缓存的使用在doCreateBean()的方法逻辑中,源码如下:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
	}

	if (instanceWrapper == null) {
		//得到一个BeanWrapper类型的bean对象
		instanceWrapper = this.createBeanInstance(beanName, mbd, args);
	}

	Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}

	synchronized(mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
				this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			} catch (Throwable var17) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
			}

			mbd.postProcessed = true;
		}
	}
	//判断该bean是否正在创建中,结果为true
	boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
	//earlySingletonExposure的结果为true,进入if内部逻辑
	if (earlySingletonExposure) {
		if (this.logger.isTraceEnabled()) {
			this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
		}
		//该方法中会将beanName作为Key,以lambda表达式:() -> {return this.getEarlyBeanReference(beanName, mbd, bean);}作为value
		//保存到三级缓存中
		this.addSingletonFactory(beanName, () -> {
			return this.getEarlyBeanReference(beanName, mbd, bean);
		});
	}

	Object exposedObject = bean;

	try {
		this.populateBean(beanName, mbd, instanceWrapper);
		exposedObject = this.initializeBean(beanName, exposedObject, mbd);
	} catch (Throwable var18) {
		if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
			throw (BeanCreationException)var18;
		}

		throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
	}

	if (earlySingletonExposure) {
		Object earlySingletonReference = this.getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
				String[] dependentBeans = this.getDependentBeans(beanName);
				Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
				String[] var12 = dependentBeans;
				int var13 = dependentBeans.length;

				for(int var14 = 0; var14 < var13; ++var14) {
					String dependentBean = var12[var14];
					if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
						actualDependentBeans.add(dependentBean);
					}
				}

				if (!actualDependentBeans.isEmpty()) {
					throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
				}
			}
		}
	}

	try {
		this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
		return exposedObject;
	} catch (BeanDefinitionValidationException var16) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
	}
}

从上面的方法源码知道,在addSingletonFactory()方法中会将beanName相关信息保存到三级缓存中,是以beanName作为Key,以lambda表达式:() -> {return this.getEarlyBeanReference(beanName, mbd, bean);}作为value保存在三级缓存singletonFactories的Map集合中,下面我们看下这个addSingletonFactory()方法的源码,源码如下:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized(this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {
			
			//将以beanName作为key,ObjectFactory作为value,存放到三级缓存singletonFactories的Map集合中
			this.singletonFactories.put(beanName, singletonFactory);
			
			//删除二级缓存中对应的bean信息
			this.earlySingletonObjects.remove(beanName);
			
			//将beanName存放到已创建bean的Set集合中
			this.registeredSingletons.add(beanName);
		}
	}
}

到此,spring源码中三级缓存的使用源码已经分析完成了,但是上面的源码只是一个三级缓存的使用代码,我们还是不知道具体如何解决的。这个我用文字描述,我自己感觉是说不清楚的我理解,我就用图示来表达一下我的个人的理解,理解不一定准确,也欢迎讨论。我的图示过程还是以User和Order类举例来说明。图示如下:

 到这里,三级缓存的运用就全部总结结束了,到这里,spring的主流程也就梳理结束了。对我个人来讲,到这里spring的学习就告一段落了。spring的其他细节后续再研究了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值