Spring循环依赖的“夺命连环问”,你能招架几波?

2023-10-18 21:20

本文主要是介绍Spring循环依赖的“夺命连环问”,你能招架几波?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

面试官:Spring是如何解决循环依赖问题的?

候选人:Spring用了三级缓存来解决这个问题

面试官:能具体讲讲它的工作原理吗?

候选人:啊这……

Spring循环依赖其实是Spring当中非常典型的一个问题,也非常难的一道题,因为回答这个问题本身会特别绕,而且这不仅仅是一道题这么简单,它后面会引发面试官一系列的夺命连环问。

那今天咱一起把循环依赖涉及的问题认真梳理一遍。

Spring循环依赖夺命连环问

一问:什么是循环依赖?

循环依赖指的是多个对象之间的依赖关系形成一个闭环。

我们都知道,如果在代码中,把两个或者多个Bean相互之间去持有对方的引用,就会发生循环依赖,循环依赖会导致注入出现死循环,这是Spring发生循环依赖的一个原因。

二问:Spring的循环依赖有哪几种形态?

第一种是互相依赖,也就是A依赖B,B又依赖A,它们之间形成了一个循环依赖:

第二种是三者之间的依赖,也就是A依赖B,B依赖C,C又依赖A,形成了一个循环依赖:

第三种是自我依赖,也就是说A与A之间形成的循环依赖。

现实中由于依赖层次深、关系复杂等因素, 导致循环依赖可能并不是那么一目了然。

三问:Spring设计三级缓存分别存放什么内容?

三级缓存说白了就是三个Map容器,在框架里头这种Map容器是随处可见:

第一层: 初始化完备的单例bean。

/** Cache of singleton objects: bean name to bean instance. */
private final Map singletonObjects = new 
ConcurrentHashMap<>(256);

第二层: 提前曝光的单例对象的Cache。

/** Cache of early singleton objects: bean name to bean instance. */
private final Map earlySingletonObjects = new 
HashMap<>(16);

第三层: ObjectFactory工厂bean缓存, 存储实例化后的bean Factory。

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map> singletonFactories = new 
HashMap<>(16);

四问:Spring这个三级缓存具体的工作原理是什么?

循环依赖主要是解决这个“死循环”没有“出口”的问题,只要我们找到这个“出口”,循环依赖就能迎刃而解。

我们分四个步骤来说:

  • 当我们通过getBean(A.class)去获得A对象实例的时候,Spring会先去一级缓存里边找,如果发现一级缓存没有找到BeanA,就去创建这个A的实例,添加到三级缓存并暴露Bean。
  • 这时候通过@Autowired依赖注入BeanB的时候,也就是getBean(B.class)的时候,Spring发现B在一级缓存找不到,于是B又重复第一步A的步骤,创建这个B的实例,添加到三级缓存并暴露Bean。
  • B通过@Autowired依赖注入BeanA的时候,这时候发现三级缓存找到了A的实例,这时候A如果实现AOP会先创建动态代理对象,然后把A从三级缓存移入了二级缓存中,至此B依赖注入成功,并完成了初始化工作,随即Spring把B从三级缓存移到了一级缓存里头,B就完成了整个的初始化工作。
  • 最后Spring加到了A的创建周期,A依赖注入B也就完成了,然后继续完成A的初始化工作,随即把A从二级缓存移到一级缓存。

这里我们可以做一个总结:

如果还是不理解,可以多看几遍这个动图:

一句话概括:先让最底层对象完成初始化,通过三级缓存与二级缓存提前曝光创建中的Bean,让其他Bean率先完成初始化。

五问:Spring在哪些情况下是无法解决循环依赖问题的呢?

有四种情况是无法解决的:

 

  1. 多实例Bean通过Setter注入。
  2. 通过构造器注入Bean。
  3. 单例的代理Bean通过Setter注入。
  4. 设置@DependsOn注解的Bean。

写在最后

其实,很多同学回答这个问题的时候也都知道,Spring就是使用三级缓存来处理这个问题,但是回答这个问题的难点在于,很多同学对这个问题理解不透,所以当你想要在短时间内向面试官解释清楚这个问题的时候,就会觉得有点条理不清。

以上这些都是从底层原理升华而来的具体问题,通常互联网大厂面试都是按这个套路,包括说很多基础知识像JVM、NIO、MQ等等这些也都是一样的——面试官先从框架的工作原理入手,考察你对框架原理的理解,最后再找一些实际的问题,考你对这种技术栈的综合的掌握能力,能不能解决实际的问题。

OK,回答好这个问题,关乎于你对Spring框架是否有深刻的理解,相信大家再次总结完后会有所收获。想要更多Java面试资料的请私信我!

这篇关于Spring循环依赖的“夺命连环问”,你能招架几波?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/235182

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

每天认识几个maven依赖(ActiveMQ+activemq-jaxb+activesoap+activespace+adarwin)

八、ActiveMQ 1、是什么? ActiveMQ 是一个开源的消息中间件(Message Broker),由 Apache 软件基金会开发和维护。它实现了 Java 消息服务(Java Message Service, JMS)规范,并支持多种消息传递协议,包括 AMQP、MQTT 和 OpenWire 等。 2、有什么用? 可靠性:ActiveMQ 提供了消息持久性和事务支持,确保消

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下