品牌网站建设哪个好/百度普通版下载

品牌网站建设哪个好,百度普通版下载,网站建设优化是干嘛,精品课程网站建设的国内外现状文章目录 前言一、循环依赖问题二、循环依赖的解决三、整体流程分析 前言 常见的可能存在循环依赖的情况如下: 两个bean中互相持有对方作为自己的属性。   类似于: 两个bean中互相持有对方作为自己的属性,且在构造时就需要传入&#xff1a…

文章目录

  • 前言
  • 一、循环依赖问题
  • 二、循环依赖的解决
  • 三、整体流程分析


前言

  常见的可能存在循环依赖的情况如下:

  1. 两个bean中互相持有对方作为自己的属性。
    在这里插入图片描述在这里插入图片描述  类似于:
    在这里插入图片描述
  2. 两个bean中互相持有对方作为自己的属性,且在构造时就需要传入:
    在这里插入图片描述在这里插入图片描述  类似于:
    在这里插入图片描述
  3. 在某个bean中注入自身:
    在这里插入图片描述
      其中第二种构造方法的循环依赖一般情况下是无解的,除非加上@Lazy注解。本篇重点分析第一种循环依赖Spring是如何解决的。

一、循环依赖问题

  Spring在创建一个bean时,简单来说会经过实例化bean,属性注入,初始化的操作。当出现第一种循环依赖时,可能会经历以下的过程:
  AService

  1. 去单例池中找有无AService实例,此时没有,执行doCreateBean
  2. createBeanInstance创建出AService实例。
  3. 执行AService实例的属性填充。
  4. AService的初始化、初始化前。
  5. AService的初始化后。
  6. 放入单例池。

  其中在执行AService实例的属性填充这一步,会根据@AutoWired的注入点,去寻找BService实例:

  1. 去单例池中找有无BService实例,此时没有,执行doCreateBean
  2. createBeanInstance`创建出BService实例。
  3. 执行BService实例的属性填充。
  4. BService的初始化、初始化前。
  5. BService的初始化后。
  6. 放入单例池。

  其中在执行BService实例的属性填充这一步,会根据@AutoWired的注入点,发现需要填充AService实例,这就出现了循环依赖的问题。

二、循环依赖的解决

  那么Spring是如何解决循环依赖的?主要是通过三级缓存的机制去实现的:
在这里插入图片描述singletonObjects :一级缓存 earlySingletonObjects 二级缓存 singletonFactories 三级缓存

  可以看到,首先在doCreateBean的方法中,bean实例化后,属性填充之前,先有一段图上的逻辑:

  • 判断当前的bean是否是单例的,以及是否支持循环依赖(默认是true),以及singletonsCurrentlyInCreation集合中是否包含当前bean。
  • 如果满足条件,就把当前的bean的名称,和一段lambda表达式,放入singletonFactories集合中。
	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {//单例池中没有该beanif (!this.singletonObjects.containsKey(beanName)) {//向单例工厂缓存当前bean名称以及对应的lambda表达式this.singletonFactories.put(beanName, singletonFactory);//从早期单例对象的缓存中去除当前的beanthis.earlySingletonObjects.remove(beanName);//向已注册的单例bean集合中添加当前bean名称this.registeredSingletons.add(beanName);}}}

在这里插入图片描述  这里的lambda表达式,主要是为了返回一个可以被外部提前访问的 bean 实例。注意:lambda表达式不是在此处执行,而是先放入了earlySingletonObjects集合中!

	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {//如果 Spring AOP 代理在这里介入,那么 getEarlyBeanReference() 可能会返回一个动态代理对象,而不是原始 beanexposedObject = bp.getEarlyBeanReference(exposedObject, beanName);}}return exposedObject;}

在这里插入图片描述返回可能经过 AOP 代理的 bean

在这里插入图片描述判断是否需要AOP

  并且在执行doGetBean时,会首先执行getSingleton方法:
在这里插入图片描述
  在getSingleton方法中,运用了双检锁模式,避免在加锁后其它线程已经创建并缓存了该 bean。并且上面提到的lambda表达式,会在此处真正地去执行

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 尝试从单例池中获取当前 bean 的实例,避免加锁操作,提高性能Object singletonObject = this.singletonObjects.get(beanName);// 如果单例池(一级缓存)中没有找到,并且当前 bean 正在创建过程中(循环依赖的处理)if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 尝试从早期单例池(二级缓存)中获取当前 bean(即尚未完全初始化的对象)singletonObject = this.earlySingletonObjects.get(beanName);// 如果在早期单例池中也没有找到,并且允许获取早期引用(通常是为了解决循环依赖)if (singletonObject == null && allowEarlyReference) {// 加锁,避免并发创建同一个 bean 导致不一致的问题synchronized (this.singletonObjects) {// 再次检查,避免在加锁后其它线程已经创建并缓存了该 beansingletonObject = this.singletonObjects.get(beanName);// 如果单例池中依然没有找到该 beanif (singletonObject == null) {// 尝试从早期单例池中获取,如果仍然没有找到singletonObject = this.earlySingletonObjects.get(beanName);// 如果早期单例池中也没有找到,尝试从工厂中获取 bean(即懒加载)if (singletonObject == null) {// 获取 bean 的工厂方法(三级缓存)ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);// 如果工厂方法存在,说明该 bean 尚未初始化,且支持懒加载if (singletonFactory != null) {// 使用工厂创建 bean 并缓存到早期单例池中,防止循环依赖singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject); // 缓存早期对象this.singletonFactories.remove(beanName); // 移除工厂方法,因为 bean 已经创建}}}}}}// 返回获取到的 singletonObject,如果没有找到,则返回 nullreturn singletonObject;
}

  这里的isSingletonCurrentlyInCreation方法,是判断当前的bean名称是否在singletonsCurrentlyInCreation集合中,那么bean是在什么时候存入该集合的呢?答案是在下方重载的getSingleton方法中:
在这里插入图片描述在这里插入图片描述在这里插入图片描述无论if条件是否成立,都会把当前的bean名称放入singletonsCurrentlyInCreation集合中

  而在执行完createBean(包括实例化,依赖注入,初始化)之后,会执行addSingleton方法:
在这里插入图片描述
  会将当前bean从二级、三级缓存中移除,并放入单例池中,表示该bean已经完全创建完成。

protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {//将当前初始化完成的bean存入单例池(一级缓存)this.singletonObjects.put(beanName, singletonObject);//从三级缓存中删除当前beanthis.singletonFactories.remove(beanName);//从二级缓存中删除当前beanthis.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}

三、整体流程分析

在这里插入图片描述A和B的创建流程 蓝色代表A 绿色代表B

  A尝试从单例池中获取
在这里插入图片描述  条件不满足,返回null
在这里插入图片描述  进入getSingleton
在这里插入图片描述
  进入getSingleton,执行beforeSingletonCreation,将A放入singletonsCurrentlyInCreation中,代表A正在被创建。
在这里插入图片描述  进入doCreateBeanaddSingletonFactory方法:
在这里插入图片描述  进入doCreateBeanaddSingletonFactory方法,将A放入三级缓存中
在这里插入图片描述  执行A的属性填充(A有一个属性为B):
在这里插入图片描述  尝试从容器中获取B
在这里插入图片描述在这里插入图片描述  这里的条件依旧不满足,返回null:
在这里插入图片描述  进入getSingleton,执行beforeSingletonCreation,同样将B放入singletonsCurrentlyInCreation中,代表B正在被创建。
在这里插入图片描述  进入doCreateBeanaddSingletonFactory

在这里插入图片描述  同样将B放入三级缓存
在这里插入图片描述


  此时的缓存情况:A和B只在二级缓存中
在这里插入图片描述


  进行B的属性填充**(B中有一个A属性)**
在这里插入图片描述  再次尝试从容器中获取A
在这里插入图片描述在这里插入图片描述  此时的条件满足:
在这里插入图片描述  从三级缓存中取出A的lambda表达式执行:
在这里插入图片描述在这里插入图片描述  此时的AB属性是没有值的
在这里插入图片描述  放入二级缓存,并从三级缓存中删除:
在这里插入图片描述


  此时的缓存情况:
在这里插入图片描述


  直接返回,不走createBean的逻辑了。
在这里插入图片描述
  给BA属性赋值,完成属性填充:
在这里插入图片描述  B继续执行初始化

在这里插入图片描述  执行BgetSingletonaddSingleton方法,将B放入单例池,并且清除二三级缓存:
在这里插入图片描述  回到A的属性填充,填充了B属性
在这里插入图片描述  填充完成后,A的B属性有值了,B的A属性也有值了,继续执行A的初始化,完成后将A放入单例池,并且清除二三级缓存:在这里插入图片描述


  此时的二三级缓存全部清空:
在这里插入图片描述


  至此整个流程全部结束。
  为什么要加入三级缓存?因为上面的过程只是普通情况,还需要考虑到AOP的情况。如果开启了AOP,那么会在初始化后,**基于切面生成一个代理对象。**而循环依赖的触发时机是在属性注入时,如果只使用普通的缓存,会导致解决循环依赖时注入的对象是普通对象,而最终的对象是代理对象,产生不一致的情况。
  applyBeanPostProcessorsAfterInitialization是初始化后执行的方法,也是在AOP的场景下生成代理对象的方法:
在这里插入图片描述  如果开启了AOP,那么在循环中会执行AbstractAutoProxyCreatorpostProcessAfterInitialization方法生成代理,在这一步中会判断当前Bean是否已经在解决了循环依赖的过程中进行了AOP,如果已经进行过了,就不会再次生成代理,保证代理对象的唯一性。
在这里插入图片描述

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

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

相关文章

Docker 部署 Jenkins持续集成(CI)工具

[TOC](Docker 部署 Jenkins持续集成(CI)工具) 前言 Jenkins 是一个流行的开源自动化工具&#xff0c;广泛应用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;的环境中。通过 Docker 部署 Jenkins&#xff0c;可以简化安装和配置过程&#xff0c;并…

《Effective Objective-C》阅读笔记(中)

目录 接口与API设计 用前缀避免命名空间冲突 提供“全能初始化方法” 实现description方法 尽量使用不可变对象 使用清晰而协调的命名方式 方法命名 ​编辑类与协议命名 为私有方法名加前缀 理解OC错误模型 理解NSCopying协议 协议与分类 通过委托与数据源协议进行…

C++程序员内功修炼——Linux C/C++编程技术汇总

在软件开发的宏大版图中&#xff0c;C 语言宛如一座巍峨的高山&#xff0c;吸引着无数开发者攀登探索。而 Linux 操作系统&#xff0c;以其开源、稳定、高效的特性&#xff0c;成为了众多开发者钟爱的开发平台。将 C 与 Linux 相结合&#xff0c;就如同为开发者配备了一把无坚不…

嵌入式八股文(五)硬件电路篇

一、名词概念 1. 整流和逆变 &#xff08;1&#xff09;整流&#xff1a;整流是将交流电&#xff08;AC&#xff09;转变为直流电&#xff08;DC&#xff09;。常见的整流电路包括单向整流&#xff08;二极管&#xff09;、桥式整流等。 半波整流&#xff1a;只使用交流电的正…

精选案例展 | 智己汽车—全栈可观测驱动智能化运营与成本优化

本案例为“观测先锋 2024 可观测平台创新应用案例大赛”精选案例&#xff0c;同时荣获IT168“2024技术卓越奖评选-年度创新解决方案”奖。 项目背景 近年来&#xff0c;中国汽车行业进入转型升级阶段&#xff0c;智能网联技术成为行业发展的核心。车联网、自动驾驶等技术的加速…

速通HTML

目录 HTML基础 1.快捷键 2.标签 HTML进阶 1.列表 a.无序列表 b.有序列表 c.定义列表 2.表格 a.内容 b.合并单元格 3.表单 a.input标签 b.单选框 c.上传文件 4.下拉菜单 5.文本域标签 6.label标签 7.按钮标签 8.无语义的布局标签div与span 9.字符实体 HTML…

IP离线库助力破解网络反诈难题

毫秒级响应识别异常访问 IP离线库集成全球全量IP地址的详细信息&#xff0c;包括地理地址查询、运营商、经纬度、代理识别等多种维度数据。例如&#xff1a; 当用户账号频繁从北京、越南等多地IP登录时&#xff0c;系统将自动触发风险预警&#xff1b; 检测到访问IP为已知机…

lattice hdl实现spi接口

在lattice工具链中实现SPI接口通常涉及以下步骤: 定义硬件SPI接口的管脚。配置SPI时钟和模式。编写SPI主机或从机的控制逻辑。 展示了如何在Lattice工具链中使用HDL语言(例如Verilog)来配置SPI接口: lattice工程 顶层:spi_slave_top.v `timescale 1ns/ 1ps module spi_…

Cesium@1.126.0,创建3D瓦片,修改样式

第一步&#xff1a;添加3D建筑 Cesium.createOsmBuildingsAsync()这是一个异步方法&#xff0c;所以要写在一个异步函数里 创建一个函数 const create3DBuilding async (viewer) > {try {// 添加3D建筑const tileset await Cesium.createOsmBuildingsAsync();viewer.scen…

基于 C++ Qt 的 Fluent Design 组件库 QFluentWidgets

简介 QFluentWidgets 是一个基于 Qt 的 Fluent Designer 组件库&#xff0c;内置超过 150 个开箱即用的 Fluent Designer 组件&#xff0c;支持亮暗主题无缝切换和自定义主题色。 编译示例 以 Qt5 为例&#xff08;Qt6 也支持&#xff09;&#xff0c;将 libQFluentWidgets.d…

React 源码揭秘 | 更新队列

前面几篇遇到updateQueue的时候&#xff0c;我们把它先简单的当成了一个队列处理&#xff0c;这篇我们来详细讨论一下这个更新队列。 有关updateQueue中的部分&#xff0c;可以见源码 UpdateQueue实现 Update对象 我们先来看一下UpdateQueue中的内容&#xff0c;Update对象&…

[SQL] 事务的四大特性(ACID)

&#x1f384;事务的四大特性 以下就是事务的四大特性&#xff0c;简称ACID。 原子性&#x1f4e2;事务时不可分割的最小操作单元&#xff0c;要么全部成功&#xff0c;要么全部失败。一致性&#x1f4e2;事务完成后&#xff0c;必须使所有的数据都保持一致隔离性&#x1f4e2…

DeepSeek 提示词:基础结构

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

Apache DolphinScheduler系列1-单节点部署及测试报告

文章目录 整体说明一、部署环境二、版本号三、部署方案四、部署步骤4.1、上传部署包4.2、创建外部数据库4.3、修改元数据库配置4.4、上传MySQLl驱动程序4.5、初始化外部数据库4.6、启停服务4.7、访问页面五、常见问题及解决方式5.1、时间不一致5.2、异常终止5.3、大量日志5.4、…

LLM之论文阅读——Context Size对RAG的影响

前言 RAG 系统已经在多个行业中得到广泛应用&#xff0c;尤其是在企业内部文档查询等场景中。尽管 RAG 系统的应用日益广泛&#xff0c;关于其最佳配置的研究却相对缺乏&#xff0c;特别是在上下文大小、基础 LLM 选择以及检索方法等方面。 论文原文: On the Influence of Co…

LLaMA-Factory|微调大语言模型初探索(4),64G显存微调13b模型

上篇文章记录了使用lora微调deepseek-7b&#xff0c;微调成功&#xff0c;但是微调llama3-8b显存爆炸&#xff0c;这次尝试使用qlora微调HQQ方式量化&#xff0c;微调更大参数体量的大语言模型&#xff0c;记录下来微调过程&#xff0c;仅供参考。 对过程不感兴趣的兄弟们可以直…

详解Redis如何持久化

引言 本文介绍了 Redis 的两种持久化方式&#xff1a;RDB 和 AOF。RDB 按时间间隔快照存储&#xff0c;AOF 记录写操作。阐述了它们的配置、工作原理、恢复数据的方法、性能与实践建议&#xff0c;如降低 fork 频率、控制内存等&#xff0c;还提到二者可配合使用&#xff0c;最…

HarmonyOS Design 介绍

HarmonyOS Design 介绍 文章目录 HarmonyOS Design 介绍一、HarmonyOS Design 是什么&#xff1f;1. 设计系统&#xff08;Design System&#xff09;2. UI 框架的支持3. 设计工具和资源4. 开发指南5. 与其他设计系统的对比总结 二、HarmonyOS Design 特点 | 应用场景1. Harmon…

Java 大视界 -- 基于 Java 的大数据机器学习模型压缩与部署优化(99)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

算法-图-数据结构(邻接矩阵)-BFS广度优先遍历

邻接矩阵广度优先遍历&#xff08;BFS&#xff09;是一种用于遍历或搜索图的算法&#xff0c;以下是具体介绍&#xff1a; 1. 基本概念 图是一种非线性的数据结构&#xff0c;由顶点和边组成&#xff0c;可分为无向图、有向图、加权图、无权图等。邻接矩阵是表示图的一种数…