Spring Boot循環(huán)依賴的癥狀和解決方案
什么是循環(huán)依賴?
循環(huán)依賴是指在Spring Boot 應用程序中,兩個或多個類之間存在彼此依賴的情況,形成一個循環(huán)依賴鏈。在這種情況下,當一個類在初始化時需要另一個類的實例,而另一個類又需要第一個類的實例時,就會出現循環(huán)依賴問題。這會導致應用程序無法正確地初始化和運行,因為Spring Boot 無法處理這種循環(huán)依賴關系。
問題及癥狀
在2.6.0之前,Spring Boot會自動處理循環(huán)依賴的問題。2.6.0及之后的版本會默認檢查循環(huán)依賴,存在該問題則會報錯。
ComponentA類注入ComponentB類,ComponentB類注入ComponentA類,就會發(fā)生循環(huá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; }
錯誤
現在,2.6.0 這個版本已經默認禁止 Bean 之間的循環(huán)引用, 則基于上面的代碼,會報錯:
*************************** 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)依賴是指兩個或更多的組件之間存在著互相依賴的關系。在Spring Boot應用程序中,循環(huán)依賴通常是由以下幾種情況引起的:
- 構造函數循環(huán)依賴:兩個或更多的組件在它們的構造函數中互相依賴。
- 屬性循環(huán)依賴:兩個或更多的組件在它們的屬性中互相依賴。
- 方法循環(huán)依賴:兩個或更多的組件在它們的方法中互相依賴。
Spring Boot提供了一些解決循環(huán)依賴的方法:
- 構造函數注入:在構造函數中注入依賴項,而不是在屬性中注入。
- Setter注入:使用setter方法注入依賴項,而不是在構造函數中注入。
- 延遲注入:使用@Lazy注解延遲加載依賴項。
- @Autowired注解的required屬性:將required屬性設置為false,以避免出現循環(huán)依賴問題。
- @DependsOn注解:使用@DependsOn注解指定依賴項的加載順序,以避免出現循環(huán)依賴問題
構造器注入的案例
假設有以下兩個類:
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; } }
通過構造函數注入可以避免循環(huán)依賴,改造后的代碼如下:
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 實例時,只需要將 B 實例傳遞給 A 的構造函數即可,不需要再通過 setter 方法將 B 實例注入到 A 中。同理,在創(chuàng)建 B 實例時,只需要將 A 實例傳遞給 B 的構造函數即可,不需要再通過 setter 方法將 A 實例注入到 B 中。這樣可以避免循環(huán)依賴。
延遲注入的案例
假設有如下情景:
類A依賴于類B,同時類B也依賴于類A。這樣就形成了循環(huán)依賴。
為了解決這個問題,可以使用@Lazy注解,將類A或類B中的其中一個延遲加載。
例如,我們可以在類A中使用@Lazy注解,將類A延遲加載,這樣在啟動應用程序時,Spring容器不會立即加載類A,而是在需要使用類A的時候才會進行加載。這樣就避免了循環(huá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; } //... }
在類A中,我們使用了@Lazy注解,將類B延遲加載。這樣在啟動應用程序時,Spring容器不會立即加載類B,而是在需要使用類B的時候才會進行加載。
這樣就避免了類A和類B之間的循環(huán)依賴問題。
接口隔離的案例
假設有兩個類A和B,它們之間存在循環(huán)依賴:
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; } }
這時候,如果直接在Spring Boot中注入A和B,就會出現循環(huán)依賴的問題。為了解決這個問題,可以使用接口隔離。
首先,定義一個接口,包含A和B類中需要使用的方法:
public interface Service { void doSomething(); }
然后,在A和B類中分別注入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實現類:
@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() { // ... } }
通過這種方式,A和B類不再直接依賴于彼此,而是依賴于同一個接口。同時,Spring Boot也能夠正確地注入A、B和ServiceImpl,避免了循環(huán)依賴的問題。
到此這篇關于Spring Boot循環(huán)依賴的癥狀和解決方案的文章就介紹到這了,更多相關解決Spring Boot循環(huán)依賴內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot 利用MultipartFile上傳本地圖片生成圖片鏈接的實現方法
這篇文章主要介紹了SpringBoot 利用MultipartFile上傳本地圖片生成圖片鏈接的實現方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03新手小白學JAVA 日期類Date SimpleDateFormat Calendar(入門)
本文主要介紹了JAVA 日期類Date SimpleDateFormat Calendar,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10