java面试题Spring部分(四)

news2024/11/15 6:57:52

一、什么事spring的三级缓存

典型回答

在Spring的BeanFactory体系中,BeanFactory是Spring IOC容器的基础接口,其DefaultSingletonBeanRegistry类实现了BeanFactory接口,并维护了三级缓存:

public class DefaultSingletonBeanRegistyr extends SimpleAliasRegistry implements SingletonBeanRegistry {
  //一级缓存,保存完成的Bean对象
  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  //三级缓存,保存单例Bean的创建工厂
  private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  //二级缓存,存储"半成品"的Bean对象
  private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
}

**singletonObjects是一级缓存,存储的是完整创建好的单例bean对象。**在创建一个单例bean时,会先从singletonObjects中尝试获取该bean的实例,如果能够获取到,则直接返回该实例,否则继续创建该bean。

**earlySingletonObjects是二级缓存,存储的是尚未完全创建好的单例bean对象。**在创建单例bean时,如果发现该bean存在循环依赖,则会先创建该bean的"半成品"对象,并将"半成品"对象存储到earlySingletonObjects中。当循环依赖的bean创建完成后,Spring会将完整的bean实例对象存储到singletonObjects中,并将earlySingletonObjects中存储的代理对象替换为完整的bean实例对象。这样可以保证单例bean的创建过程不会出现循环依赖问题。

**singletonFactories是三级缓存,存储的是单例bean的创建工厂。**当一个单例bean被创建时,Spring会先将该bean的创建工厂存储到singletonFactories中,然后再执行创建工厂的getObject()方法,生成该bean的实例对象。在该bean被其他bean引用时,Spring会从singletonFactories中获取该bean的创建工厂,创建出该bean的实例对象,并将该bean的实例对象存储到singletonObjects中。

二、Spring解决循环依赖一定需要三级缓存吗

典型回答

使用二级缓存也能解决循环依赖问题,但是如果完全依赖二级缓存解决循环依赖,意味着当我们依赖了一个代理类的时候,就需要在Bean实例化之后完成AOP代理,而在Spring的设计中,为了了解Bean的初始化和代理,是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理的。
但是,在Spring的初始化过程中,他是不知道哪些Bean可能有循环依赖的,那么,这时候Spring面临两个选择:

  1. 不管有没有循环依赖,都提前把代理对象创建出来,并将代理对象缓存起来,出现循环依赖时,其他对象直接就可以取到代理对象并注入。
  2. 不提前创建代理对象,在出现循环依赖时,再生成代理对象。这样在没有循环依赖的情况下,Bean就可以按着Spring设计原则的步骤来创建。

第一个方案看上去比较简单,只需要二级缓存就可以了。但是他也意味着,Spring需要在所有的bean的创建过程中就要先成代理对象再初始化;那么这就和spring的aop的设计原则(前文提到的:在Spring的设计中,为了解耦Bean的初始化和代理,是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理的)是相悖的。

而Spring为了不破坏AOP的代理设计原则,则引入第三级缓存,在三级缓存中保存对象工厂,因为通过对象工厂我们可以在想要创建对象的时候直接获取对象。有了它,在后续发生循环依赖时,如果依赖的Bean被AOP代理,那么通过这个工厂获取到的就是代理后的对象,如果没有被AOP代理,那么这个工厂获取到的就是实例化的真实对象。

三、三级缓存是如何解决循环依赖问题的

典型回答

**Spring中Bean的创建过程其实可以分为两步:第一步实例化,第二步初始化
实例化的过程只需要调用构造函数把对象创建出来并给他分配空间,而初始化则是给对象的属性进行赋值。
而Spring之所以可以解决循环依赖就是因为对象的初始化是可以延后的,也就是说,当我创建一个Bean Service的时候,会先把这个对象实例化出来,然后再初始化其中的serviceB属性。

@Service
public class Service{

	@Autowired
	private ServiceB serviceB;
}

@Service
public class ServiceB{

	@Autowired
	private ServiceA serviceA;
}

而 当一个对象只进行了实例化,但是还没有进行初始化时,我们称之为半成品对象。所以,所谓半成品对象,其实就是bean对象的空壳子,还没有进行属性注入和初始化。

当两个Bean在初始化过程中互相依赖的时候,如初始化A发现依赖了B,继续去初始化B,发现又依赖了A。大致流程如下图:
在这里插入图片描述
以上方法,就是通过引入三级缓存,解决了循环依赖的问题,在上述流程执行完成之后,ServiceA和ServiceB都被成功的完成了实例化和初始化。
以下是DefaultSingletonBeanRegistry#getSingleton方法,代码中,包括一级缓存、二级缓存、三级缓存的处理逻辑,该方法是获取bean的单例实例对象的核心方法:

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 首先从一级缓存中获取bean实例对象,如果已经存在,则直接返回
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 如果一级缓存中不存在bean实例对象,而且当前bean正在创建中,则从二级缓存中获取bean实例对象
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            // 如果二级缓存中也不存在bean实例对象,并且允许提前引用,则需要在锁定一级缓存之前,
            // 先锁定二级缓存,然后再进行一系列处理
            synchronized (this.singletonObjects) {
                // 进行一系列安全检查后,再次从一级缓存和二级缓存中获取bean实例对象
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        // 如果二级缓存中也不存在bean实例对象,则从三级缓存中获取bean的ObjectFactory,并创建bean实例对象
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            // 将创建好的bean实例对象存储到二级缓存中
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            // 从三级缓存中移除bean的ObjectFactory
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1974209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在OpenHarmony 4.1R上设置系统默认不锁屏(修改系统锁屏应用)

本文介绍如何修改系统锁屏应用&#xff0c;从而实现在OpenHarmony 4.1R上设置系统默认不锁屏。 环境配置 1.DevEco Studio 4.1 Release&#xff0c;下载链接地址 API10 Full SDK,安装教程 步骤 1.首先下载4.1r分支的系统锁屏应用applications_screenlock 2.修改系统锁屏应…

【Plotly-驯化】一文画出漂亮的流量漏斗图:plotly.funnel函数使用技巧

【Plotly-驯化】一文画出漂亮的流量漏斗图&#xff1a;plotly.funnel函数使用技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获…

HTML+CSS練習---空隙產生記錄

1.第一層和第二層之間的間隙&#xff1a;以為導航欄超過高度朝下擠下來了 2.第2層兩個div中的空隙 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title><style>font-face {f…

ATTCK实战系列-红队评估 (一)Vulnstack三层网络域渗透

目录 一、搭建环境 1.靶场下载地址&#xff1a; 2、网络拓扑 3、环境配置 Win7&#xff08;外网服务器 &#xff09; Win2008&#xff08;域控&#xff09; Win2003&#xff08;域成员&#xff09; 4、启动环境 二、信息收集 1、端口扫描 2、目录扫描 三、漏洞利用…

IM即时通讯客服聊天系统源码(某站售8千)

即时通讯客服聊天系统已经成为企业提供卓越客户服务的不可或缺的工具。为了帮助您快速搭建强大的客服聊天系统&#xff0c;提供了一款全面的源码模板&#xff0c;基于Java和Spring Boot微服务架构构建&#xff0c;支持多种功能模块&#xff0c;以及消息加密、红包、消息撤回等功…

基于JSP的学生综合考评管理系统

你好&#xff0c;我是专注于教育信息化的开发者&#xff0c;很高兴为您介绍本系统。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSPJava 工具&#xff1a;Eclipse、MySQL数据库管理工具 系统展示 首页 管理员功能 教师功能 学生功能 摘要 本文…

笔记本怎么手动设置ip地址:一步步教你操作

在使用笔记本电脑连接网络时&#xff0c;有时候我们需要手动设置IP地址以满足特定的网络需求或解决网络问题。手动设置IP地址可以帮助我们更好地控制网络连接&#xff0c;确保设备在网络中的稳定性和安全性。然而&#xff0c;对于不熟悉网络设置的用户来说&#xff0c;手动设置…

EPLAN EDZ 文件太大导入很慢如何解决?

目前各个品牌都在提供 EPLAN EDZ部件库文件,但是一般都是一个总的EDZ文件,导入过程中,因为电脑配置和其他问题,导致导入过程中EPLAN会崩溃或者长时间不动。 我们分析下EDZ文件的构成,这是个压缩文件,换了个壳而已。用压缩软件把edz打开,这里不是解压,直接右键,用解压…

[CP_AUTOSAR]_系统服务_DEM模块(二)功能规范介绍

目录 1、DEM 功能规范描述1.1、Startup behavior1.2、Monitor re-initialization 在前面 《[CP_AUTOSAR]_系统服务_DEM模块&#xff08;一&#xff09;》文中&#xff0c;简要介绍了 DEM 模块的功能、与其它模块之间的功能交互&#xff0c;本文将接着介绍 DEM 模块的功能规范。…

Web前端:Vue开发环境搭建

一、搭建开发环境&#xff1a; 1.nodejs安装&#xff1a; 下载地址&#xff1a; https://nodejs.org/dist/v20.13.1/node-v20.13.1-x64.msi 查看版本号&#xff1a; node -v 2.安装nrm(用于指定国内镜像源&#xff0c;加速依赖包下载速度)&#xff1a; 安装nrm&#xff…

程序员的魔法石!

本文由 ChatMoney团队出品 AI自己写代码&#xff0c;这只是传说&#xff1f;还是摸鱼新指南&#xff1f; AI出现之前&#xff0c;从来都是老板或产品经理提需求&#xff0c;程序员熬夜加班吭哧吭哧写代码或者是从Github&#xff0c;Stackoverflow上controlc&#xff0c;control…

为面试准备的一些内容

开发中使用了什么技术&#xff1f; mvvm、compose、livedata、单例模式、工厂模式、弱引用、线程池、Handler。 对于项目一开始我们打算使用aosp原生的管控方式&#xff0c;如UsageStatManager获取每个app的使用时长&#xff0c;和使用PackageManager的setPackagesSuspended方…

【数据结构入门 】栈

目录 前言 一、栈的概念及结构 二、栈的实现 1. 栈的声明 2.初始化栈 3. 栈的销毁 4.判断是否为空栈 5.入栈&#xff08;只能插入栈顶元素&#xff09; 6. 出栈&#xff08;只能从栈顶删除&#xff09; 7.栈的大小 8.获取栈顶元素 总结 前言 在计算机科学中&#xf…

黑马Java零基础视频教程精华部分_10_面向对象进阶(2)

系列文章目录 文章目录 系列文章目录一、多态1、什么是多态&#xff1f;2、多态的表现形式3、多态的前提4、多态的好处5、多态调用成员的特点6、多态的优势和弊端7、引用数据类型的类型转换 二、包1、什么是包&#xff1f;2、包名的规则3、使用其他类的规则 三、final 最终的&a…

文件包含漏洞Tomato靶机渗透_详解

一、导入靶机 将下载好的靶机拖入到VMware中&#xff0c;填写靶机机名称(随便起一个)和路径 虚拟机设置里修改网络状态为NAT模式 二、信息收集 1、主机发现 用御剑扫描工具扫描虚拟机的NAT网段&#xff0c;发现靶机的IP是192.168.204.141 2、端口扫描 用御剑端口扫描扫描全…

完全免费的 TTS 文字转语音来了!

作者&#xff1a;老余捞鱼 原创不易&#xff0c;转载请标明出处及原作者。 完全免费的 TTS 文字转语音来了&#xff01; 再也不用被国内外各种语音合成割韭菜了。 试了下&#xff0c;确实是不限次数&#xff0c;不限语种&#xff0c;完全免费.输出视频如下&#xff1a; 效果就…

springboot干部考核系统-计算机毕业设计源码74229

摘要 随着我国社会经济的快速发展&#xff0c;对干部队伍的素质要求越来越高&#xff0c;如何科学、公正、准确地评价干部的工作绩效&#xff0c;激励干部发挥出更大的工作潜能&#xff0c;成为了当务之急。近年来&#xff0c;计算机技术和网络技术的飞速发展&#xff0c;为干部…

Minetest大师:1.0.21版本发布

下载Minetest大师v1.0.21 1、简介 Minetest大师&#xff0c;一款致力于Minetest的游戏盒子 可加Q群-&#xff1a;123117246&#xff0c;了解或获取最新版本 2、增加了大量的基础功能 资源中心与ContentDB同步&#xff0c;增加资源搜索、安装功能 增加在线服务器列表&#…

Python 爬虫入门(五):使用 lxml 解析网页

Python 爬虫入门&#xff08;五&#xff09;&#xff1a;使用 lxml 解析网页 前言1. lxml 简介1.1 什么是 lxml&#xff1f;1.2 为什么选择 lxml&#xff1f;1.3 安装 lxml 2. lxml 基础2.1 解析 HTML/XML2.2 XPath 表达式2.3 使用 XPath 提取数据 3. 深入解析3.1 处理命名空间…

HarmonyOS应用开发者高级认证题目(7月新版,答案解析,持续更新)

HarmonyOS应用开发者高级认证题目&#xff08;7月新版&#xff0c;答案&解析&#xff0c;持续更新&#xff09; 单选 1.ArkTS支持以下哪些函数 A.Object.getOwnPropertySymbols(); B.Object.isExtensible(); C.Object.isPrototypeOf(); D.Object.keys(); 答案&#xff1…