溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Spring?Boot循環(huán)依賴(lài)怎么解決

發(fā)布時(shí)間:2023-05-08 17:06:30 來(lái)源:億速云 閱讀:266 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“Spring Boot循環(huán)依賴(lài)怎么解決”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Spring Boot循環(huán)依賴(lài)怎么解決”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

    什么是循環(huán)依賴(lài)?

    循環(huán)依賴(lài)是指在Spring Boot 應(yīng)用程序中,兩個(gè)或多個(gè)類(lèi)之間存在彼此依賴(lài)的情況,形成一個(gè)循環(huán)依賴(lài)鏈。在這種情況下,當(dāng)一個(gè)類(lèi)在初始化時(shí)需要另一個(gè)類(lèi)的實(shí)例,而另一個(gè)類(lèi)又需要第一個(gè)類(lèi)的實(shí)例時(shí),就會(huì)出現(xiàn)循環(huán)依賴(lài)問(wèn)題。這會(huì)導(dǎo)致應(yīng)用程序無(wú)法正確地初始化和運(yùn)行,因?yàn)镾pring Boot 無(wú)法處理這種循環(huán)依賴(lài)關(guān)系。

    問(wèn)題及癥狀

    在2.6.0之前,Spring Boot會(huì)自動(dòng)處理循環(huán)依賴(lài)的問(wèn)題。2.6.0及之后的版本會(huì)默認(rèn)檢查循環(huán)依賴(lài),存在該問(wèn)題則會(huì)報(bào)錯(cuò)。

    ComponentA類(lèi)注入ComponentB類(lèi),ComponentB類(lèi)注入ComponentA類(lèi),就會(huì)發(fā)生循環(huán)依賴(lài)的問(wèn)題。

    ComponentA

    import org.springframework.stereotype.Service;
    import javax.annotation.Resource;
     
    @Service
    public class ComponentA {
    
        @Resource
        private ComponentB componentB;
     
    }

    ComponentB

    import org.springframework.stereotype.Service;
    import javax.annotation.Resource;
     
    @Service
    public class ComponentB {
     
        @Resource
        private ComponentA componentA;
     
    }

    錯(cuò)誤

    現(xiàn)在,2.6.0 這個(gè)版本已經(jīng)默認(rèn)禁止 Bean 之間的循環(huán)引用, 則基于上面的代碼,會(huì)報(bào)錯(cuò):

    ***************************
    APPLICATION FAILED TO START
    ***************************
    
    Description:
    
    The dependencies of some of the beans in the application context form a cycle:
    
    ┌─────┐
    |  componentA
    ↑     ↓
    |  componentB
    └─────┘
    
    
    Action:
    
    Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

    解決方法

    循環(huán)依賴(lài)是指兩個(gè)或更多的組件之間存在著互相依賴(lài)的關(guān)系。在Spring Boot應(yīng)用程序中,循環(huán)依賴(lài)通常是由以下幾種情況引起的:

    • 構(gòu)造函數(shù)循環(huán)依賴(lài):兩個(gè)或更多的組件在它們的構(gòu)造函數(shù)中互相依賴(lài)。

    • 屬性循環(huán)依賴(lài):兩個(gè)或更多的組件在它們的屬性中互相依賴(lài)。

    • 方法循環(huán)依賴(lài):兩個(gè)或更多的組件在它們的方法中互相依賴(lài)。

    Spring Boot提供了一些解決循環(huán)依賴(lài)的方法:

    1. 構(gòu)造函數(shù)注入:在構(gòu)造函數(shù)中注入依賴(lài)項(xiàng),而不是在屬性中注入。

    2. Setter注入:使用setter方法注入依賴(lài)項(xiàng),而不是在構(gòu)造函數(shù)中注入。

    3. 延遲注入:使用@Lazy注解延遲加載依賴(lài)項(xiàng)。

    4. @Autowired注解的required屬性:將required屬性設(shè)置為false,以避免出現(xiàn)循環(huán)依賴(lài)問(wèn)題。

    5. @DependsOn注解:使用@DependsOn注解指定依賴(lài)項(xiàng)的加載順序,以避免出現(xiàn)循環(huán)依賴(lài)問(wèn)題

    構(gòu)造器注入的案例

    假設(shè)有以下兩個(gè)類(lèi):

    public class A {
        private B b;
    
        public A() {
            // ...
        }
    
        public void setB(B b) {
            this.b = b;
        }
    }
    
    public class B {
        private A a;
    
        public B() {
            // ...
        }
    
        public void setA(A a) {
            this.a = a;
        }
    }

    通過(guò)構(gòu)造函數(shù)注入可以避免循環(huán)依賴(lài),改造后的代碼如下:

    public class A {
        private B b;
    
        public A(B b) {
            this.b = b;
        }
    }
    
    public class B {
        private A a;
    
        public B(A a) {
            this.a = a;
        }
    }

    這樣,在創(chuàng)建 A 實(shí)例時(shí),只需要將 B 實(shí)例傳遞給 A 的構(gòu)造函數(shù)即可,不需要再通過(guò) setter 方法將 B 實(shí)例注入到 A 中。同理,在創(chuàng)建 B 實(shí)例時(shí),只需要將 A 實(shí)例傳遞給 B 的構(gòu)造函數(shù)即可,不需要再通過(guò) setter 方法將 A 實(shí)例注入到 B 中。這樣可以避免循環(huán)依賴(lài)。

    延遲注入的案例

    假設(shè)有如下情景:

    類(lèi)A依賴(lài)于類(lèi)B,同時(shí)類(lèi)B也依賴(lài)于類(lèi)A。這樣就形成了循環(huán)依賴(lài)。

    為了解決這個(gè)問(wèn)題,可以使用@Lazy注解,將類(lèi)A或類(lèi)B中的其中一個(gè)延遲加載。

    例如,我們可以在類(lèi)A中使用@Lazy注解,將類(lèi)A延遲加載,這樣在啟動(dòng)應(yīng)用程序時(shí),Spring容器不會(huì)立即加載類(lèi)A,而是在需要使用類(lèi)A的時(shí)候才會(huì)進(jìn)行加載。這樣就避免了循環(huán)依賴(lài)的問(wèn)題。

    示例代碼如下:

    @Component
    public class A {
    
        private final B b;
    
        public A(@Lazy B b) {
            this.b = b;
        }
    
        //...
    }
    
    @Component
    public class B {
    
        private final A a;
    
        public B(A a) {
            this.a = a;
        }
    
        //...
    }

    在類(lèi)A中,我們使用了@Lazy注解,將類(lèi)B延遲加載。這樣在啟動(dòng)應(yīng)用程序時(shí),Spring容器不會(huì)立即加載類(lèi)B,而是在需要使用類(lèi)B的時(shí)候才會(huì)進(jìn)行加載。

    這樣就避免了類(lèi)A和類(lèi)B之間的循環(huán)依賴(lài)問(wèn)題。

    接口隔離的案例

    假設(shè)有兩個(gè)類(lèi)A和B,它們之間存在循環(huán)依賴(lài):

    public class A {
        private final B b;
        public A(B b) {
            this.b = b;
        }
    }
    
    public class B {
        private final A a;
        public B(A a) {
            this.a = a;
        }
    }

    這時(shí)候,如果直接在Spring Boot中注入A和B,就會(huì)出現(xiàn)循環(huán)依賴(lài)的問(wèn)題。為了解決這個(gè)問(wèn)題,可以使用接口隔離。

    首先,定義一個(gè)接口,包含A和B類(lèi)中需要使用的方法:

    public interface Service {
        void doSomething();
    }

    然后,在A和B類(lèi)中分別注入Service接口:

    public class A {
        private final Service service;
        public A(Service service) {
            this.service = service;
        }
    }
    
    public class B {
        private final Service service;
        public B(Service service) {
            this.service = service;
        }
    }

    最后,在Spring Boot中注入Service實(shí)現(xiàn)類(lèi):

    @Service
    public class ServiceImpl implements Service {
        private final A a;
        private final B b;
        public ServiceImpl(A a, B b) {
            this.a = a;
            this.b = b;
        }
        @Override
        public void doSomething() {
            // ...
        }
    }

    通過(guò)這種方式,A和B類(lèi)不再直接依賴(lài)于彼此,而是依賴(lài)于同一個(gè)接口。同時(shí),Spring Boot也能夠正確地注入A、B和ServiceImpl,避免了循環(huán)依賴(lài)的問(wèn)題。

    讀到這里,這篇“Spring Boot循環(huán)依賴(lài)怎么解決”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI