自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

意料之中、要求3-5年的Leader,最后選了應(yīng)屆生

開發(fā) 前端
Spring無法解決構(gòu)造函數(shù)導(dǎo)致的循環(huán)依賴,是因?yàn)樵趯ο髮?shí)例化的過程中,構(gòu)造函數(shù)都是最早被調(diào)用的,那個(gè)時(shí)候?qū)ο筮€沒完成實(shí)例化,所以沒辦法注入一個(gè)尚未完成創(chuàng)建的對象。

閑談

大家好,我是了不起,前段時(shí)間,了不起在當(dāng)面試官,挑了許多人給leader去面談,最后可能是因?yàn)榘阎澳硞€(gè)想走的同事留了下來了,所以對新人沒有太多的要求,所以選了應(yīng)屆生。

感覺如果是這種情況,還是比較利好應(yīng)屆生的,不然有些業(yè)務(wù)比較特殊的活,需要有能力接下上一任的工作,對面試的人要求會(huì)非常的高,人也不好找,最后頭疼的也是我。

不提也罷,回歸正題,分享一道最近常用來面試1-2年工作經(jīng)驗(yàn)的人的面試題吧。

什么是Spring的循環(huán)依賴問題

圖片圖片

在軟件開發(fā)的世界里,我們總是追求代碼的優(yōu)雅與高效。目前Java主流的SpringBoot、SpringCloud框架無疑是我們最好的幫手。它不僅簡化了企業(yè)級(jí)應(yīng)用的開發(fā),還為我們提供了許多強(qiáng)大的功能。

比如依賴注入DI,但是,就像任何技術(shù)都有其雙刃劍的一面,依賴注入也不例外,Spring在進(jìn)行依賴注入時(shí)最常見的一個(gè)問題——循環(huán)依賴。

舉例一個(gè)場景,我們有兩個(gè)Service類A和B,A類里有個(gè)a2方法需要調(diào)用了B類里的b1方法,B類里的b2方法需要用到A類里的a1方法。

圖片圖片

那么按照我們Java代碼的無腦編程,就會(huì)是下面的這個(gè)情況:

ServiceA的a2方法調(diào)用ServiceB里的b1方法。

@Service
public class ServiceA implements Service {

    @Autowired
    private ServiceB serviceB;
    
    @Override
    public void a1() {
        System.out.println("當(dāng)前是ServiceA的a1方法"");
    }
                           
    @Override
    public void a2() {
        System.out.println("這里將調(diào)用ServiceB的b1方法");
        serviceB.b1();
    }
}

同樣ServiceB的b2方法就調(diào)用ServiceA里的a1方法。

@Service
public class ServiceB implements Service{

    @Autowired
    private ServiceA serviceA;

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

    @Override
    public void b2() {
        System.out.println("這里將調(diào)用ServiceA的a1方法");
        serviceA.a1();
    }
    
}

運(yùn)行結(jié)果

當(dāng)你運(yùn)行這個(gè)SpringBoot應(yīng)用的時(shí)候,會(huì)遇到一個(gè)錯(cuò)誤,錯(cuò)誤信息如下:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'serviceA': Requested bean is currently in creation: Is there an unresolvable circular reference?

拓展復(fù)習(xí)

還記得Bean的創(chuàng)建過程嗎?Spring 在啟動(dòng)時(shí)會(huì)根據(jù)配置文件或注解來創(chuàng)建和初始化所有的bean。這個(gè)過程可以分為幾個(gè)階段:

  1. 實(shí)例化(Instantiation):Spring 容器創(chuàng)建一個(gè)bean的實(shí)例。
  2. 屬性填充(Population of Properties):Spring 容器設(shè)置bean的所有屬性,包括依賴注入。
  3. 初始化(Initialization):Spring 容器調(diào)用bean的初始化方法(如 @PostConstruct 注解的方法或 InitializingBean 接口的 afterPropertiesSet 方法)。

現(xiàn)在我們有兩個(gè)bean:ServiceA 和 ServiceB,它們相互依賴對方。具體來說:

  • ServiceA 依賴 ServiceB
  • ServiceB 依賴 ServiceA

當(dāng)Spring嘗試創(chuàng)建 ServiceA 時(shí),它會(huì)發(fā)現(xiàn) ServiceA 需要 ServiceB。于是Spring開始創(chuàng)建 ServiceB。然而,在創(chuàng)建 ServiceB 的過程中,Spring 又發(fā)現(xiàn) ServiceB 需要 ServiceA。這時(shí),Spring 發(fā)現(xiàn)自己已經(jīng)在一個(gè)創(chuàng)建 ServiceA 的過程中,從而導(dǎo)致了一個(gè)循環(huán)依賴。

圖片圖片

好比這張圖一樣,把箭頭的方向可以理解成前提條件,是不是就一目了然了。彼此成為對方的前提條件。就好比,不考慮進(jìn)化論,究竟是先雞還是先蛋?

回歸正題

在開發(fā)中,一般遇到這個(gè)問題,通常會(huì)使用@Lazy來解決。

@Service
public class ServiceB implements Service{

    @Autowired
    @Lazy
    private ServiceA serviceA;

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

    @Override
    public void b2() {
        System.out.println("這里將調(diào)用ServiceA的a1方法");
        serviceA.a1();
    }
}

它一方面可以減少Spring的IOC容器在啟動(dòng)時(shí)的加載時(shí)間,一方面也可以解決Bean的循環(huán)依賴問題。

但是這是在日常開發(fā)使用的時(shí)候的處理方法,面試的時(shí)候肯定不會(huì)就這么放過你。

所以我們在面試的時(shí)候遇到這個(gè)問題,通常還會(huì)再多回答兩個(gè)方式。

Spring解決循環(huán)依賴必須是單例的Bean

這是一種依賴Spring提前暴露對象的方式來實(shí)現(xiàn)的。這種也叫半成品對象,通過對上面的學(xué)習(xí),我們知道了循環(huán)依賴的原因是因?yàn)樵趧?chuàng)建的時(shí)候需要引用到另一個(gè)正在創(chuàng)建的對象,通過暴露這種半成品對象,讓初始化的時(shí)候能夠解決循環(huán)依賴的問題。

但是這種方式不能使用在原型對象的創(chuàng)建和初始化!背過面試題的都知道:

  1. 單例對象的特點(diǎn):

單例對象在整個(gè)容器生命周期內(nèi)只會(huì)被創(chuàng)建一次。

這種特性使得單例對象的依賴關(guān)系在容器啟動(dòng)時(shí)就已經(jīng)確定下來,不會(huì)發(fā)生變化。

  1. 原型對象的特點(diǎn):

原型對象在每次請求時(shí)都會(huì)創(chuàng)建新的實(shí)例。

對于原型對象而言,每次創(chuàng)建新實(shí)例時(shí)都可能涉及到不同的對象實(shí)例,因此不能像單例那樣緩存并復(fù)用半成品對象。

不支持構(gòu)造函數(shù)注入

Spring無法解決構(gòu)造函數(shù)導(dǎo)致的循環(huán)依賴,是因?yàn)樵趯ο髮?shí)例化的過程中,構(gòu)造函數(shù)都是最早被調(diào)用的,那個(gè)時(shí)候?qū)ο筮€沒完成實(shí)例化,所以沒辦法注入一個(gè)尚未完成創(chuàng)建的對象。

因此,解決循環(huán)依賴的一種方式,就是避開構(gòu)造函數(shù)注入。

結(jié)論

上面的知識(shí)只是給你科普用的,不是讓你用來回答的。如果你實(shí)在不理解,那就背下面的吧!

  1. 重新設(shè)計(jì),徹底消除循環(huán)依賴(是一句廢話沒錯(cuò),但是面試得講一下)
  2. 改成非構(gòu)造器注入的形式,比如setter注入或者字段注入
  3. 使用@Lazy解決
責(zé)任編輯:武曉燕 來源: Java面試教程
相關(guān)推薦

2010-11-04 10:14:13

職場

2013-01-09 08:59:13

20122013iOS

2020-12-13 17:47:44

物聯(lián)網(wǎng)安全連接性IOT

2018-07-30 16:32:25

應(yīng)屆生認(rèn)知誤區(qū)

2010-10-28 11:15:13

求職

2010-11-16 10:14:22

2021-05-12 13:56:05

手機(jī)華為蘋果

2009-04-01 08:31:47

索尼錄用應(yīng)屆大學(xué)生

2012-10-30 15:50:02

應(yīng)屆生團(tuán)隊(duì)就業(yè)

2012-06-04 09:20:19

程序員

2009-11-24 10:45:01

2009-03-25 09:15:33

面試騰訊趨勢

2009-02-01 15:40:07

2015-10-26 14:29:54

服務(wù)器開發(fā)應(yīng)屆生

2015-10-15 10:49:09

服務(wù)器開發(fā)虛擬化應(yīng)屆生

2013-07-01 12:19:00

大學(xué)生IT博客大賽IT博客大賽博客大賽

2010-12-15 15:28:40

職場

2018-03-08 14:39:40

華為速度業(yè)務(wù)

2020-01-10 17:21:09

應(yīng)屆生月薪薪資

2017-10-31 11:39:42

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)