網站首頁 編程語言 正文
1.什么是循環依賴?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
顧名思義:循環+依賴 ;
? ? ? ? - 類與類之間的依賴關系形成了閉環。
?常見的循環依賴有以下三種情況:
?- 自身依賴于自身
?- 互相循環依賴
?- 多組循環依賴
2.代碼演示依賴
public class YanshiTest {
public static void main(String[] args) {
new Test1();
}
}
class Test1{
private Test2 test2 = new Test2();
}
class Test2{
private Test1 test1 = new Test1();
}
?Test1 依賴 Test2? ? ?Test2 依賴 Test1
我們執行代碼后結果:
Exception in thread "main" java.lang.StackOverflowError
at com.ape.test.Test2.<init>(YanshiTest.java:21)
at com.ape.test.Test1.<init>(YanshiTest.java:17)
at com.ape.test.Test2.<init>(YanshiTest.java:21)
at com.ape.test.Test1.<init>(YanshiTest.java:17)
at com.ape.test.Test2.<init>(YanshiTest.java:21)
at com.ape.test.Test1.<init>(YanshiTest.java:17)
at com.ape.test.Test2.<init>(YanshiTest.java:21)
at com.ape.test.Test1.<init>(YanshiTest.java:17)
at com.ape.test.Test2.<init>(YanshiTest.java:21)
at com.ape.test.Test1.<init>(YanshiTest.java:17)
at com.ape.test.Test2.<init>(YanshiTest.java:21)
at com.ape.test.Test1.<init>(YanshiTest.java:17)
這樣的循環循環了很多行才停,出現了StackOverflowError 的錯誤,這就是循環依賴。
3.如何解決
首先我們進行原因分析:
????????-? ?Test1在構造方法中需要獲取Test2的對象,然后在創建Test2中有需要Test1的對象。
解決問題的關鍵是我們要把對象的創建拆分為:
? ? ? ? -? 構造方法
? ? ? ? -? 成員變量賦值 ==》get/set 方法處理
首先先給Test1 與Test2 寫GET/SET方法
public class YanshiTest {
public static void main(String[] args) {
System.out.println( new Test1().getTest2());
}
}
class Test1{
private Test2 test2;
public Test2 getTest2() {
return test2;
}
public void setTest2(Test2 test2) {
this.test2 = test2;
}
}
class Test2{
private Test1 test1 ;
public Test1 getTest1() {
return test1;
}
public void setTest1(Test1 test1) {
this.test1 = test1;
}
}
-??需要把構造方法與屬性賦值 作為一個整體?
-? 需要提供一個獲取實例的方法
? ? ? ? 這個方法需要 根據類型獲取一個對應的實例對象 因此定義為泛型
? ? ? ? 這個方法需要 完成構造? 完成成員變量的賦值
public static <T> T getBean(Class<T> classname) throws Exception{
//1.通過構造方法獲取實例對象
Object t = classname.newInstance();
//2.給成員變量賦值
Field[] fields = classname.getDeclaredFields();
//遍歷
for (Field field : fields) {
//賦值
field.setAccessible(true);
Class<?> type = field.getType();
field.set(t,getBean(type));
}
return (T)t;
}
此時我們在main方法進行調用還是會報錯,因此我們需要拆解來看
首先 我們想如果把獲取的實例對象存儲到Map容器 再去獲取需要的對象時,就不需要去new了,直接從map里面取出賦值給Test02,這樣就不會出現循環依賴了,但是這個map是個半成品,因此我們需要做一些操作:
//存儲半成品的容器——解決循環依賴
private static final Map<String,Object> map =new ConcurrentHashMap<String, Object>();
此時只需兩步
? ? ? ? 1.判斷map是否有對象
? ? ? ? 2.沒有就放進去
public static <T> T getBean(Class<T> classname) throws Exception{
//--獲取類型的名稱
String beanName = classname.getSimpleName().toLowerCase();
//--如果map中有對象直接返回
if(map.containsKey(beanName)){
return (T)map.get(beanName);
}
//1.通過構造方法獲取實例對象
Object t = classname.newInstance();
//--創建的這個半成品對象我們需要存儲在map容器中
map.put(beanName,t);
//2.給成員變量賦值
Field[] fields = classname.getDeclaredFields();
//遍歷
for (Field field : fields) {
//賦值
field.setAccessible(true);
Class<?> type = field.getType();
field.set(t,getBean(type));
}
return (T)t;
}
在進行運行:
?
解決掉了,完美撒花。? 解決這個的關鍵點在于提前暴露半成品對象。
上面的方法中的核心是getBean方法,Test1 創建后填充屬性時依賴Test2,那么就去創建 Test2,在創建 Test2 開始填充時發現依賴于 Test1,但此時 Test1 這個半成品對象已經有了(其實是個緩存),所以Test2可以正常創建,在通過遞歸把 Test1 也創建完整了。
3.循環依賴
基于前面案例的了解,我們知道肯定需要在調用構造方法方法創建完成后再暴露對象,在Spring中提供了三級緩存來處理這個事情:
首先在調用構造方法的后會放入到三級緩存中--》然后在填充屬性的時候會存入二級緩存中--》最后把創建的對象保存在了一級緩存中
就是這樣啦!下個星期見!
原文鏈接:https://blog.csdn.net/weixin_67588007/article/details/126215614
相關推薦
- 2022-11-14 Python實現簡易超市管理系統_python
- 2022-09-20 Python中類的mro與繼承關系詳解_python
- 2022-08-10 Python實現以主程序的形式執行模塊_python
- 2022-07-09 Android實現app開機自啟動功能_Android
- 2022-07-10 初中級前端程序員必用且夠用的git命令同時推送到github/gitee及三種常用場景
- 2023-07-06 css flex實現div固定在瀏覽器右下角
- 2022-02-04 ImportError: No module named ‘flask_sqlalchemy‘
- 2022-04-12 React工作流程及Error?Boundaries實現過程講解_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支