Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >意料之中、要求3-5年的leader,最后选了应届生

意料之中、要求3-5年的leader,最后选了应届生

作者头像
灬沙师弟
发布于 2024-11-22 10:26:12
发布于 2024-11-22 10:26:12
9900
代码可运行
举报
文章被收录于专栏:Java面试教程Java面试教程
运行总次数:0
代码可运行

闲谈

大家好,我是了不起,前段时间,了不起在当面试官,挑了许多人给leader去面谈,最后可能是因为把之前某个想走的同事留了下来了,所以对新人没有太多的要求,所以选了应届生。

感觉如果是这种情况,还是比较利好应届生的,不然有些业务比较特殊的活,需要有能力接下上一任的工作,对面试的人要求会非常的高,人也不好找,最后头疼的也是我。

不提也罢,回归正题,分享一道最近常用来面试1-2年工作经验的人的面试题吧。

什么是Spring的循环依赖问题

软件开发的世界里,我们总是追求代码的优雅与高效。目前Java主流的SpringBoot、SpringCloud框架无疑是我们最好的帮手。它不仅简化了企业级应用的开发,还为我们提供了许多强大的功能。

比如依赖注入DI,但是,就像任何技术都有其双刃剑的一面,依赖注入也不例外,Spring在进行依赖注入时最常见的一个问题——循环依赖。

举例一个场景,我们有两个Service类A和B,A类里有个a2方法需要调用了B类里的b1方法,B类里的b2方法需要用到A类里的a1方法。

那么按照我们Java代码的无脑编程,就会是下面的这个情况:

ServiceA的a2方法调用ServiceB里的b1方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class ServiceA implements Service {

    @Autowired
    private ServiceB serviceB;
    
    @Override
    public void a1() {
        System.out.println("当前是ServiceA的a1方法"");
    }
                           
    @Override
    public void a2() {
        System.out.println("这里将调用ServiceB的b1方法");
        serviceB.b1();
    }
}

同样ServiceB的b2方法就调用ServiceA里的a1方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class ServiceB implements Service{

    @Autowired
    private ServiceA serviceA;

    @Override
    public void b1() {
        System.out.println("当前是ServiceB的b1方法");
    }

    @Override
    public void b2() {
        System.out.println("这里将调用ServiceA的a1方法");
        serviceA.a1();
    }
    
}

运行结果

当你运行这个SpringBoot应用的时候,会遇到一个错误,错误信息如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'serviceA': Requested bean is currently in creation: Is there an unresolvable circular reference?

拓展复习

还记得Bean的创建过程吗?Spring 在启动时会根据配置文件或注解来创建和初始化所有的bean。这个过程可以分为几个阶段:

  1. 实例化(Instantiation):Spring 容器创建一个bean的实例。
  2. 属性填充(Population of Properties):Spring 容器设置bean的所有属性,包括依赖注入。
  3. 初始化(Initialization):Spring 容器调用bean的初始化方法(如 @PostConstruct 注解的方法或 InitializingBean 接口的 afterPropertiesSet 方法)。

现在我们有两个bean:ServiceAServiceB,它们相互依赖对方。具体来说:

  • ServiceA 依赖 ServiceB
  • ServiceB 依赖 ServiceA

当Spring尝试创建 ServiceA 时,它会发现 ServiceA 需要 ServiceB。于是Spring开始创建 ServiceB。然而,在创建 ServiceB 的过程中,Spring 又发现 ServiceB 需要 ServiceA。这时,Spring 发现自己已经在一个创建 ServiceA 的过程中,从而导致了一个循环依赖。

好比这张图一样,把箭头的方向可以理解成前提条件,是不是就一目了然了。彼此成为对方的前提条件。就好比,不考虑进化论,究竟是先鸡还是先蛋?

回归正题

在开发中,一般遇到这个问题,通常会使用@Lazy来解决。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class ServiceB implements Service{

    @Autowired
    @Lazy
    private ServiceA serviceA;

    @Override
    public void b1() {
        System.out.println("当前是ServiceB的b1方法");
    }

    @Override
    public void b2() {
        System.out.println("这里将调用ServiceA的a1方法");
        serviceA.a1();
    }
}

它一方面可以减少Spring的IOC容器在启动时的加载时间,一方面也可以解决Bean的循环依赖问题。

但是这是在日常开发使用的时候的处理方法,面试的时候肯定不会就这么放过你。

所以我们在面试的时候遇到这个问题,通常还会再多回答两个方式。

Spring解决循环依赖必须是单例的Bean

这是一种依赖Spring提前暴露对象的方式来实现的。这种也叫半成品对象,通过对上面的学习,我们知道了循环依赖的原因是因为在创建的时候需要引用到另一个正在创建的对象,通过暴露这种半成品对象,让初始化的时候能够解决循环依赖的问题。

但是这种方式不能使用在原型对象的创建和初始化!背过面试题的都知道:

  1. 单例对象的特点:
    • 单例对象在整个容器生命周期内只会被创建一次。
    • 这种特性使得单例对象的依赖关系在容器启动时就已经确定下来,不会发生变化。
  2. 原型对象的特点:
    • 原型对象在每次请求时都会创建新的实例。
    • 对于原型对象而言,每次创建新实例时都可能涉及到不同的对象实例,因此不能像单例那样缓存并复用半成品对象。

不支持构造函数注入

Spring无法解决构造函数导致的循环依赖,是因为在对象实例化的过程中,构造函数都是最早被调用的,那个时候对象还没完成实例化,所以没办法注入一个尚未完成创建的对象。

因此,解决循环依赖的一种方式,就是避开构造函数注入。

结论

上面的知识只是给你科普用的,不是让你用来回答的。如果你实在不理解,那就背下面的吧!

  1. 重新设计,彻底消除循环依赖(是一句废话没错,但是面试得讲一下)
  2. 改成非构造器注入的形式,比如setter注入或者字段注入
  3. 使用@Lazy解决
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java面试教程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
年薪50万的一个面试题,看着不难,却刷掉了99%的人!
今天要说的是spring中循环依赖的问题,最近有大量粉丝问这个问题,也是高薪面试中经常会被问到的一个问题。
路人甲Java
2020/05/18
1.5K0
年薪50万的一个面试题,看着不难,却刷掉了99%的人!
最新整理Spring面试题2023
好了,不开玩笑,面对这个问题我们应该怎么来回答呢?我们给大家梳理这个几个维度来回答
用户4919348
2023/03/08
2.3K0
最新整理Spring面试题2023
使用Mockito修改Bean的依赖
在使用单元测试时经常会遇到某些dependency依赖了外部资源,或者想主动绕过真正的方法执行mock返回结果而快速得到单元测试最终的期望结果,可能有以下两种场景, 对于TestCase A,设单元测试的方法是Service A的execute1方法和execute2方法,在执行execute1和execute2方法时都会调用ServiceB的不同方法,即ServiceA依赖了ServiceB;一个场景是完全对ServiceB进行Mock,如单元测试ServiceA#execute1方法时都通过Mock返回结果;一个场景是部分ServiceB的方法执行真实的业务逻辑(如查询数据库),一部分方法执行Mock返回结果,或Spy,如如单元测试ServiceA#execute2方法时,只mock ServiceB#b2结果,真正执行ServiceB#b1方法。
用户3579639
2018/10/22
2K0
Dependency Injection: 如何解决依赖注入失败问题
大家好,我是默语,擅长全栈开发、运维和人工智能技术。依赖注入(Dependency Injection)是现代软件开发中的一项关键技术,用于实现组件解耦和提高代码可维护性。然而,依赖注入有时会遇到一些问题,例如注入失败、循环依赖等。本文将深入探讨依赖注入失败的原因及解决方案,帮助大家更好地使用依赖注入技术。
默 语
2024/11/22
3130
Spring如何解决循环依赖
那么Spring是如何解决这种问题呢?今天来分析一下。不过需要先熟悉下Bean的生命周期:宏观来看Bean的生命周期分为四步:1.实例化 2.属性设置 3.初始化 4.销毁。对依赖注入而言在第二步属性设置其实已经完成了,所以只需要关注前两步即可。
默 语
2024/11/22
2260
Spring如何解决循环依赖
今日头条面试,这个问题让我与50万擦肩而过,帮忙看看!
我:当某个类上有@Configuration注解的时候,可以在这个类中使用@Bean注解向spring容器中注册bean;如果不加@Configuration注解,不能通过@Bean注解注册bean。
路人甲Java
2020/03/26
6070
Spring是如何解决循环依赖的?
A对象,它的属性是B对象,而B对象的属性也是A对象,说白了就是A依赖B,而B又依赖A
Blue_007
2023/10/21
3320
Spring是如何解决循环依赖的?
Spring系列第14篇:单例bean中使用多例bean,你未必会玩?
通常情况下,我们使用的bean都是单例的,如果一个bean需要依赖于另一个bean的时候,可以在当前bean中声明另外一个bean引用,然后注入依赖的bean,此时被依赖的bean在当前bean中自始至终都是同一个实例。
路人甲Java
2020/03/12
2.6K0
Spring中循环依赖解决方案
循环依赖是Spring框架中常见的问题之一,当两个或多个类相互引用对方时,就会出现循环依赖的情况。这种情况下,Spring框架无法确定哪个类应该先实例化和初始化,从而导致异常。常见的解决方法有:构造函数注入、setter方法注入、静态工厂方法注入以及使用第三方库等。
鱼找水需要时间
2023/08/16
7.4K0
Spring中循环依赖解决方案
Spring基础
Spring框架是一个全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层,主要包括以下七个模块:
羽毛球初学者
2024/10/22
1440
Spring系列面试题
@Controller注解 是在Spring的org.springframework.stereotype包下,org.springframework.stereotype.Controller注解类型用于指示Spring类的实例是一个控制器,使用@Controller注解的注解注解的控制器可以同时支持处理多个请求动作,使程序开发变的更加灵活。 @Controller用户标记一个类,使用它标记的类就是一个Spring MVC Controller对象,即:一个控制器类。Spring使用扫描机制查找应用程序中所有基于注解的控制器类,分发处理器会扫描使用了该注解的方法,并检测该方法是否使用了@RequestMapping注解,而使用@RequestMapping注解的方法才是真正处理请求的处理器。为了保证Spring能找到控制器,我们需要完成两件事:
用户3467126
2019/09/30
7330
Spring系列面试题
Spring系列第十九讲 @Configuration和@Bean注解详解
@Configuration这个注解可以加在类上,让这个类的功能等同于一个bean xml配置文件,如下:
易兮科技
2020/11/24
15K1
Spring解决循环依赖的思路
循环依赖也就是循环引用,指两个或多个对象互相持有对方的引用。通俗地说,假设在Spring中有3个Service Bean,分别为ServiceA、ServiceB和ServiceC,如果ServiceA引用了ServiceB,ServiceB引用了ServiceC,而ServiceC又引用了ServiceA,最终形成可一个环,这样就出现了循环依赖。
张申傲
2020/09/03
6970
Spring系列第10篇:primary可以解决什么问题?
上面代码很简单,@1:定义了一个接口IService,@2和@3创建了两个类都实现了IService接口。
路人甲Java
2020/02/26
8200
面经手册 · 第31篇《Spring Bean IOC、AOP 循环依赖解读》
大学有四年时间,但几乎所有人都是临近毕业才发现找一份好工作费劲,尤其是我能非常熟悉的软件开发行业,即使是毕业了还需要额外花钱到培训机构,在学一遍编程技术才能出去找工作。好像在校这几年压根就没学到什么!
小傅哥
2021/05/17
4490
面经手册 · 第31篇《Spring Bean IOC、AOP 循环依赖解读》
Spring官网阅读系列(二):Spring依赖注入及方法注入
上篇文章我们学习了官网中的1.2,1.3两小节,主要是涉及了容器,以及Spring实例化对象的一些知识。这篇文章我们继续学习Spring官网,主要是针对1.4小节,主要涉及到Spring的依赖注入。虽然只有一节,但是涉及的东西确不少。话不多说,开始正文。
秃顶的Java程序员
2020/03/24
4640
面试专题-框架篇
refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 ApplicationContext 容器,容器必须调用 refresh 才能正常工作。它的内部主要会调用 12 个方法,我们把它们称为 refresh 的 12 个步骤:
sgr997
2022/11/10
4800
面试专题-框架篇
这么回答【循环依赖】助力轻松拿下阿里P6
  上图是循环依赖的三种情况,虽然方式有点不一样,但是循环依赖的本质是一样的,就你的完整创建要依赖与我,我的完整创建也依赖于你。相互依赖从而没法完整创建造成失败。
用户4919348
2022/10/04
2290
这么回答【循环依赖】助力轻松拿下阿里P6
Spring系列第11篇:bean中的autowire-candidate又是干什么的?
上一篇文章Spring系列第10篇:primary可以解决什么问题?中遇到的问题我们再来回顾一下,当容器中某种类型的bean存在多个的时候,此时如果我们从容器中查找这种类型的bean的时候,会报下面这个异常:
路人甲Java
2020/02/26
2.4K0
烂了大街的 Spring 循环依赖问题,你觉得自己会了吗
初学 Spring 的时候,我们就知道 IOC,控制反转么,它将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,不需要我们手动去各种 new XXX。
海星
2020/09/09
7120
相关推荐
年薪50万的一个面试题,看着不难,却刷掉了99%的人!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验