Spring源码之IoC,单例Bean添加到一、二、三级缓存的时机,源码解读

news/2024/4/19 11:28:47/文章来源:https://blog.csdn.net/weixin_43073775/article/details/129251386

目录

  • 添加到一级缓存的时机
    • doGetBean方法中创建单例Bean的代码
    • getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法源码
    • addSingleton方法源码
  • 添加到二级缓存的时机
    • doGetBean中首次调用getSingleton
  • 添加到三级缓存的时机
    • doGetBean方法调用addSingletonFactory方法的源码
    • addSingletonFactory方法源码
  • 总结

三个缓存都存在于DefaultSingletonBeanRegistry中。以AbstractBeanFactory中的getBean作为入口。

添加到一级缓存的时机

一级缓存主要用于存储单例模式下创建完毕的Bean实例,包括该Bean的实例化,依赖注入,初始化等都完成的一个完整的Bean。

所以添加到一级缓存中的时机:自然是完成Bean的实例化,依赖注入,初始化等操作,生成完整的单例Bean后进行添加的。

源码位置:getBean方法——doGetBean方法——getSingleton创建单例Bean——addSingleton方法

doGetBean方法中创建单例Bean的代码

可以看到,getSingleton方法的入参传入是ObjectFactory类型,使用匿名内部类的方式,传入一个实现了ObjectFactory类的getObject方法的对象,getObject方法通过调用createBean方法完成对象的创建。

                if (mbd.isSingleton()) {sharedInstance = this.getSingleton(beanName, () -> {try {return this.createBean(beanName, mbd, args);} catch (BeansException var5) {this.destroySingleton(beanName);throw var5;}});beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}

getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法源码

1、该方法使用synchronized对一级缓存进行加锁。
2、获取到锁后从一级缓存中取Bean对象,取到则直接返回
3、缓存中取不到,则调用ObjectFactory的getObject方法创建对象
4、最后调用addSingleton方法,把单例Bean添加到缓存中

    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 {singletonObject = singletonFactory.getObject();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);}if (newSingleton) {this.addSingleton(beanName, singletonObject);}}return singletonObject;}}

addSingleton方法源码

1、该方法使用synchronized对一级缓存进行加锁。获取singletonObjects锁
2、调用put方法添加到一级缓存
3、清理三级缓存singletonFactories中的该Bean
4、清理二级缓存earlySingletonObjects中的该Bean
5、把该Bean添加到成功列表中,registeredSingletons记录已经创建成功的单例名称。

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

添加到二级缓存的时机

源码位置:getBean方法——doGetBean方法——getSingleton方法

doGetBean中首次调用getSingleton

getSingleton(beanName)此方法先从一级和二级缓存中取,如果都取不到,允许从三级缓存中取,如果从三级缓存中取到Bean。

如果从三级缓存中取到对应的Bean,则把Bean添加到二级缓存,并在三级缓存中清除

    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {String beanName = this.transformedBeanName(name);Object sharedInstance = this.getSingleton(beanName);
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized(this.singletonObjects) {singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 添加到二级缓存this.earlySingletonObjects.put(beanName, singletonObject);// 在三级缓存中清除this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}

添加到三级缓存的时机

调用createBeanInstance进行Bean实例化之后,调用populateBean进行依赖注入之前

源码位置:getBean方法——doGetBean方法——addSingletonFactory方法

doGetBean方法调用addSingletonFactory方法的源码

        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {if (this.logger.isTraceEnabled()) {this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");}this.addSingletonFactory(beanName, () -> {return this.getEarlyBeanReference(beanName, mbd, bean);});}

addSingletonFactory方法源码

1、获取锁
2、添加到三级缓存
3、从二级缓存中进行清理
4、把该Bean添加到成功列表中,registeredSingletons记录已经创建成功的单例名称。

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

总结

添加到一级缓存:完成Bean的实例化,依赖注入,初始化等操作,生成完整的单例Bean后进行添加。

添加到二级缓存:通过getBean获取实例,在三级缓存中获取到时,添加到二级缓存,并清理三级缓存。

添加到三级缓存:通过createBeanInstance实例化Bean之后,调用populateBean进行依赖注入之前。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux文件属性--软连接和硬链接

文章目录软链接硬链接软链接和硬链接的区别软链接 软链接&#xff08;Soft Link&#xff09;又叫符号链接&#xff08;Symbolic Link &#xff09;&#xff0c;是linux特殊文件的一种&#xff0c;文件类型为l,它的数据是它所链接的文件或目录的路径。软链接可以跨磁盘和 分区…

动手学深度学习(第二版)学习笔记 第三章

第三章 线性神经网络 代码&#xff1a;d2l-zh/pytorch/chapter_linear-networks 3.1 线性回归 3.1. 线性回归 — 动手学深度学习 2.0.0 documentation 解析解 线性回归的解可以用一个公式简单地表达出来&#xff0c;这类解叫作解析解&#xff08;analytical solution&…

git在工作中的正常使用

开发A和B功能后进行发版。。 一、拉取代码 git clone http://ntc.ntsvars.com:8090/lvweijie/test.git二、开发功能A任务 创建A任务本地分支 #创建A分支&#xff0c;并切换A分支 git checkout -b A三、开发A任务 四、提交A功能文件到本地分支 git add .五、添加提交A功能备…

AcWing3485. 最大异或和

先看题目&#xff1a; 说实话&#xff0c;我看到这道题就想用滑动窗口&#xff0c;但是滑了一下发现不太对啊&#xff0c;如果我用滑动窗口的话&#xff0c;那么最后肯定是一个固定长度为m的窗口在持续计算&#xff0c;区间长度小于m的区间的异或和肯定会被遗漏。然后我就想怎么…

FSP:Flow of Solution Procedure (CVPR 2017) 原理与代码解析

paper&#xff1a;A Gift From Knowledge Distillation: Fast Optimization, Network Minimization and Transfer Learningcode&#xff1a;https://github.com/HobbitLong/RepDistiller/blob/master/distiller_zoo/FSP.py背景深度神经网络DNN逐层生成特征。更高层的特征更接近…

决策树在sklearn中的实现

目录 一.模块sklearn.tree 二.建模基本流程 三.DecisionTreeClassifier重要参数 1.criterion 2.random_state & splitter 3.剪枝参数max_depth 4.剪枝参数min_samples_leaf & min_samples_split 5.max_features & min_impurity_decrease 6.class_weight …

Python IDE:对于 Python 初学者来说,最好的 IDE 是什么?

Python 是科技界最简单、使用最广泛的编程语言之一。它是一种高级通用编程语言&#xff0c;强调代码可读性并使用面向对象的方法。Python可以用来完成很多任务&#xff0c;包括网站开发、软件开发、 自动化 和数据分析 专业开发人员使用Python开发各种流行的软件程序&#xff0…

深入理解Spring MVC上

Spring MVC 是一种基于 Spring 框架的 Web 框架&#xff0c;它提供了一种基于 Model-View-Controller&#xff08;MVC&#xff09;的设计模式&#xff0c;用于构建 Web 应用程序。在 Spring MVC 中&#xff0c;Controller 接受并处理 HTTP 请求&#xff0c;并将其转发给适当的 …

多表left join 慢sql问题

作为个人记录&#xff0c;后续再填坑a对p是1对多 ,p对llup 1对多SELECTa.id,p.id,t1.id FROMliv_series_product aINNER JOIN liv_product p ON p.id a.product_idLEFT JOIN ( SELECT llup.id, llup.product_id, llup.room_id FROM liv_live_user_product llup WHERE llup.ro…

Tomcat部署及多实例

Tomcat部署及多实例一、Tomcat简介1、Tomcat核心组件2、什么是JSP二、Tomcat数据流向1、Tomcat数据流向2、Tomcat-Nginx数据流向三、Tomcat服务部署安装1、安装jdk包2、解压Tomcat所需的安装包3、在/etc/profile添加环境变量4、启动服务并查看5、在浏览器网页验证6、创建用户&a…

为什么硬件性能监控很重要

当今的混合网络环境平衡了分布式网络和现代技术的实施。但它们并不缺少一个核心组件&#xff1a;服务器。保持网络正常运行时间归结为监控和管理导致网络停机的因素。极有可能导致性能异常的此类因素之一是硬件。使用硬件监控器监控网络硬件已成为一项关键需求。 硬件监视器是…

优化知识管理方法丨整理零碎信息,提高数据价值

信息流时代&#xff0c;知识成集合倍数增长&#xff0c;看似我们学习了很多知识&#xff0c;但知识零碎无系统&#xff0c;知识之间缺乏联系&#xff0c;没有深度&#xff0c;所以虽然你很努力&#xff0c;但你发现自己的能力增长特别缓慢&#xff0c;你需要整理知识将零散的知…

蓝桥杯:染色时间

蓝桥杯&#xff1a;染色时间https://www.lanqiao.cn/problems/2386/learning/?contest_id80 问题描述 输入格式 输出格式 样例输入输出 样例输入 样例输出 评测用例规模与约定 解题思路&#xff1a;优先队列 AC代码(Java)&#xff1a; 问题描述 小蓝有一个 n 行 m 列…

std::chrono笔记

文章目录1. radio原型作用示例2. duration原型&#xff1a;作用示例3. time_point原型作用示例4. clockssystem_clock示例steady_clock示例high_resolution_clock先说感觉&#xff0c;这个库真恶心&#xff0c;刚接触感觉跟shi一样&#xff0c;特别是那个命名空间&#xff0c;太…

vue2 diff算法

diff是什么 diff 算法是一种通过同层的树节点进行比较的高效算法 其有两个特点&#xff1a; ♥比较只会在同层级进行, 不会跨层级比较 ♥在diff比较的过程中&#xff0c;循环从两边向中间比较 diff 算法的在很多场景下都有应用&#xff0c;在 vue 中&#xff0c;作用于虚拟 dom…

预备2-CMD常用命令

CMD常用命令 先学简单常用的, 其余的要用在学 打开Cmd窗口 Win键R> 输入Cmd回车鼠标点击开始 > 附件>Cmd打开一个窗口,在地址栏输入cmd 操作目录 1.dir 查询当前目录有哪些文件 2.cd.. 上一级目录 3.cd e: 切换到E盘 4.d: 直接去d盘 5.cd /d e:abc 直接去E盘的abc目…

2023年房地产行业研究报告

第一章 行业发展概况 房地产业是指以土地和建筑物为经营对象&#xff0c;从事房地产开发、建设、经营、管理以及维修、装饰和服务的集多种经济活动为一体的综合性产业&#xff0c;是具有先导性、基础性、带动性和风险性的产业。主要包括&#xff1a;土地开发&#xff0c;房屋的…

解决AAC音频编码时间戳的计算问题

1.主题音频是流式数据&#xff0c;并不像视频一样有P帧和B帧的概念。就像砌墙一样&#xff0c;咔咔往上摞就行了。一般来说&#xff0c;AAC编码中生成文件这一步&#xff0c;如果使用的是OutputStream流写入文件的话&#xff0c;就完全不需要计算时间。但在音视频同步或者使用A…

debian 部署nginx https

我是flask 处理请求单进程&#xff0c; 差点意思 &#xff0c; 考虑先flask 在往下走 一&#xff1a;安装nginx 因为我是debian 系统&#xff0c;所以我的建议是直接 sudo apt-get install nginx 你也可以选择在官网下载&#xff0c; 但是我搭建ssl 的时候安装openssl非常的麻…

【无标题】(2019)NOC编程猫创新编程复赛小学组真题含参考

&#xff08;2019&#xff09;NOC编程猫创新编程复赛小学组最后6道大题。前10道是选择填空题 略。 这道题是绘图题&#xff0c;没什么难度&#xff0c;大家绘制这2个正十边形要注意&#xff1a;一是不要超出舞台&#xff1b;二是这2个正十边形不要相交。 这里就不给出具体程序了…