Spring源码解析-三级缓存与循环依赖,整理了3家面试问题:美团+字节+腾讯

// 从各级缓存中获取bean对象

Object sharedInstance = getSingleton(beanName);

// 这个判断是跟factoryBean相关的

if (sharedInstance != null && args == null) {

if (logger.isTraceEnabled()) {

if (isSingletonCurrentlyInCreation(beanName)) {

logger.trace(“Returning eagerly cached instance of singleton bean '” + beanName +

“’ that is not fully initialized yet - a consequence of a circular reference”);

}

else {

logger.trace(“Returning cached instance of singleton bean '” + beanName + “'”);

}

}

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

}

// 创建bean对象

if (mbd.isSingleton()) {

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);

}

// 返回bean对象

return (T) bean;

}

我们重点看两个getSingleton()方法

// 这段代码三级缓存容器都涉及到了,初看有点懵,但是思路不难,先从一级缓存找,找不到去二级缓存找,还找不到去三级缓存

// 如果在三级缓存找到了,就放到二级缓存中,非常像数据库跟redis的缓存策略,先到redis中找,找不到去数据库找,找到再写到redis中

protected Object getSingleton(String beanName, boolean allowEarlyReference) {

// 先从一级缓存中找bean

Object singletonObject = this.singletonObjects.get(beanName);

// 这里有两个判断,singletonObject == null 表示在一级缓存中找不到bean

// isSingletonCurrentlyInCreation()表示该bean是否在创建中

// 如果两个条件满足,说明出现了循环依赖

if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {

synchronized (this.singletonObjects) {

// 再从二级缓存中获取

singletonObject = this.earlySingletonObjects.get(beanName);

// 这里又有两个判断

// singletonObject == null 表示在二级缓存中没有获取到

// allowEarlyReference 这个值传进来就为true,表示是否允许获取早期引用

// 如果两个条件都满足,就到三级缓存中获取

if (singletonObject == null && allowEarlyReference) {

// 从三级缓存获取,注意,这里获取到是一个ObjectFactory

ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);

if (singletonFactory != null) {

// 通过ObjectFactory获取bean实例

singletonObject = singletonFactory.getObject();

// 打怪升级,从三级缓存升级到二级缓存,

this.earlySingletonObjects.put(beanName, singletonObject);

this.singletonFactories.remove(beanName);

}

}

}

}

// 返回bean

return singletonObject;

}

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

Assert.notNull(beanName, “Bean name must not be null”);

synchronized (this.singletonObjects) {

// 从一级缓存中获取bean

Object singletonObject = this.singletonObjects.get(beanName);

// 如果bean为空

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 + “'”);

}

// 单例bean创建前会将这个bean放到一个容器中,标志这个bean正在创建中

beforeSingletonCreation(beanName);

boolean newSingleton = false;

boolean recordSuppressedExceptions = (this.suppressedExceptions == null);

if (recordSuppressedExceptions) {

this.suppressedExceptions = new LinkedHashSet<>();

}

try {

// 执行匿名内部类方法

singletonObject = singletonFactory.getObject();

newSingleton = true;

}

catch (IllegalStateException ex) {

singletonObject = this.singletonObjects.get(beanName);

if (singletonObject == null) {

throw ex;

}

}

catch (BeanCreationException ex) {

if (recordSuppressedExceptions) {

for (Exception suppressedException : this.suppressedExceptions) {

ex.addRelatedCause(suppressedException);

}

}

throw ex;

}

finally {

if (recordSuppressedExceptions) {

this.suppressedExceptions = null;

}

// 单例bean创建完成后,会把bean从这个容器中移除

afterSingletonCreation(beanName);

}

// newSingleton为true时,表示bean创建成功

if (newSingleton) {

// 把bean放到一级缓存中,一级缓存就是我们常说的IOC容器

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);

}

}

从上面的代码我们已经可以总结出bean没有出现循环依赖时,流程是怎么样的?

  1. getSingleton()方法查看是否存在于一级缓存中,是则获取,无则走下面的创建流程,因为没有出现循环依赖,isSingletonCurrentlyInCreation(beanName),此判断是false

  2. createBean()方法创建一个bean

  3. addSingleton()方法将bean放到一级缓存中

当然,在正常的流程中会穿插异常流程的处理方式,比如bean创建前会把bean放到一个容器中,Spring凭借这个可以知道bean是否正在创建中,得知bean在创建中后,会利用三级缓存获得bean空壳

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

throws BeanCreationException {

// mbd.isSingleton():bean是否是单例

// this.allowCircularReferences:是否允许出现循环依赖

// isSingletonCurrentlyInCreation(beanName):bean是否在创建中

// 如果三个条件都满足,说明出现了循环依赖

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&

isSingletonCurrentlyInCreation(beanName));

if (earlySingletonExposure) {

if (logger.isTraceEnabled()) {

logger.trace(“Eagerly caching bean '” + beanName +

“’ to allow for resolving potential circular references”);

}

// 将bean放到三级缓存中

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

}

// Initialize the bean instance.

Object exposedObject = bean;

try {

// 属性赋值

populateBean(beanName, mbd, instanceWrapper);

// bean初始化

exposedObject = initializeBean(beanName, exposedObject, mbd);

}

catch (Throwable ex) {

if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {

throw (BeanCreationException) ex;

}

else {

throw new BeanCreationException(

mbd.getResourceDescription(), beanName, “Initialization of bean failed”, ex);

}

}

// 如果出现了循环依赖

if (earlySingletonExposure) {

// 从各级缓存中获取bean,getSingleton(beanName, false)这个方法是不是很熟悉,上面已经使用到了

// 只是第二个参数从true变成了false,这个参数决定了要不要从第三级缓存中获取数据

// 代码走到这个地方,已经无需获取早期引用了,所以参数为false

Object earlySingletonReference = getSingleton(beanName, false);

// 如果二级缓存不为空

if (earlySingletonReference != null) {

// 并且二级缓存中的bean跟exposedObject相等,说明初始化时,没有使用代理修改bean对象

if (exposedObject == bean) {

// 直接将二级缓存中bean返回即可

exposedObject = earlySingletonReference;

}

return exposedObject;

}

我们重点看看addSingletonFactory()这个方法,我们先看一段简单代码,感受一下ObjectFactory这个类的作用

public class ObjectFactoryTest {

public static void main(String[] args) {

HashMap<String, ObjectFactory<?>> map = new HashMap<>(2);

map.put(“a”, () -> {

System.out.println(“objectFactory”);

return “string”;

});

System.out.println(map.get(“a”).getObject());

}

}

image.png 原来,ObjectFactory可以定制执行方法,那么Spring要定制的执行方法是什么?

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);

}

}

}

// 要定制的执行方法就是一个beanPostProcess的埋点

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {

Object exposedObject = bean;

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {

SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;

exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);

}

}

}

return exposedObject;

}

// AOP的beanPostProcess重写了这个方法

@Override

public Object getEarlyBeanReference(Object bean, String beanName) {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面

小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>

image

针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺

image

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

image

image

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

[外链图片转存中…(img-uhq5fGpV-1712189669839)]

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

[外链图片转存中…(img-eL4hb9Zd-1712189669839)]

[外链图片转存中…(img-WPKZX22M-1712189669839)]

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值