首先,我將簡單介紹一下Spring框架中的動態代理和循環依賴問題。
動態代理與循環依賴
1. 動態代理
在Spring框架中,動態代理是一種常用的技術,用于實現AOP(面向切面編程)。動態代理允許Spring在運行時為目標對象創建一個代理,以此來插入額外的邏輯,例如事務管理、日志記錄等。
2. 循環依賴
循環依賴是指兩個或多個Bean相互依賴,形成閉環,導致無法順利完成依賴注入。例如,Bean A依賴Bean B,而Bean B又依賴Bean A。
最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進大廠原來沒那么難。
這是大佬寫的,?7701頁的BAT大佬寫的刷題筆記,讓我offer拿到手軟
解決循環依賴:三級緩存
1. 三級緩存
Spring使用三級緩存解決循環依賴的問題:
- 一級緩存:存放完全初始化完成的Bean(單例池)。
- 二級緩存:存放原始Bean的早期引用。
- 三級緩存:存放Bean的ObjectFactory,用于生成Bean的代理對象。
2. 工作機制
當Spring容器創建Bean時,首先將實例化后的原始Bean放入三級緩存。如果在Bean的完全初始化之前需要引用該Bean,Spring會通過三級緩存中的ObjectFactory來創建Bean的代理對象,并將其提升到二級緩存中。這樣,即使在Bean還未完全初始化之前,也能通過代理對象來解決循環依賴的問題。
使用場景與性能優化
1. 使用場景
- 事務管理:使用動態代理管理事務邊界。
- 日志記錄:在方法執行前后添加日志記錄。
- 安全性:在方法調用前進行權限檢查。
2. 性能優化
- 減少代理創建:僅對關鍵服務進行代理,避免過度使用動態代理。
- 懶加載:適當使用懶加載,延遲Bean的初始化。
代碼示例
讓我們通過一個簡單的例子來理解Spring的動態代理和循環依賴的處理:
// 服務接口
public interface UserService {void addUser(String username);
}// 實現類
public class UserServiceImpl implements UserService {@Autowiredprivate OrderService orderService; // 依賴OrderService@Overridepublic void addUser(String username) {System.out.println("Adding user: " + username);// ... 其他邏輯 ...}
}// 另一個服務
public class OrderService {@Autowiredprivate UserService userService; // 依賴UserServicepublic void createOrder(String username) {System.out.println("Creating order for: " + username);// ... 其他邏輯 ...}
}
在這個例子中,UserService
?和?OrderService
?互相依賴。Spring通過三級緩存機制,確保這種循環依賴不會導致問題。
Spring中三級緩存機制是如何工作的,特別是在解決循環依賴的情況下。
我會用一個稍微復雜點的例子來展示這一機制。
場景設定
假設我們有兩個組件,A
?和?B
,它們互相依賴。為了簡化示例,我們假設它們都是單例(Spring默認的作用域)。
@Component
public class A {@Autowiredprivate B b;public A() {System.out.println("A 創建");}// A的其他方法...
}@Component
public class B {@Autowiredprivate A a;public B() {System.out.println("B 創建");}// B的其他方法...
}
三級緩存的工作原理
實例化:
當Spring容器啟動時,它會嘗試創建這些Bean。
首先,它創建了A的實例。在這個過程中,Spring發現A需要依賴B。
然后,它開始創建B的實例。同樣,在創建B時,發現B需要依賴A。
三級緩存介入:
此時,A的實例已經被部分創建,并存放在三級緩存中。
當Spring為B創建依賴A時,它不會重新創建A的實例。相反,它會使用存在于三級緩存中的A的早期引用。
這個早期引用足以滿足B對A的依賴,從而允許B的創建過程繼續。
依賴注入與完成創建:
一旦B被成功創建,Spring會完成對A的依賴注入。
這時,A和B都已經被完全創建,并存放在Spring的一級緩存(即單例池)中。
關鍵點
這個過程中的“早期引用”通常是通過使用ObjectFactory創建的代理對象。
三級緩存主要用于解決這種循環依賴的問題,同時也確保了Spring容器的線程安全。
注意事項
雖然三級緩存機制很強大,但它僅適用于單例作用域的Bean。
對于原型作用域的Bean,Spring不會嘗試解決循環依賴,這可能會導致BeanCurrentlyInCreationException異常。
推薦一個學習?Spring源碼分析?的專欄文章
- 01、Spring源碼分析 - 01-DispatcherServlet注冊過程
- 02、Spring源碼分析 - 02-Resource
- 03、Spring源碼分析 - 03-ResourceLoader
- 04、Spring源碼分析 - 04-類型轉換
- 05、Spring源碼分析 - 05-字段格式化
- 06、Spring源碼分析 - 06-ResolvableType
- 07、Spring源碼分析 - 07-BeanWrapper
- 08、Spring源碼分析 - 08-DataBinder
- 09、Spring源碼分析 - 09-PropertySourcesPropertyResolver
- 10、Spring源碼分析 - 10-Environment
- 11、Spring源碼分析 - 11-BeanFactory的實現
- 12、Spring源碼分析 - 12-BeanFactory創建Bean的重要流程圖
- 13、Spring源碼分析 - 13-DispatcherServlet中WebApplicationContext啟動過程
- 14、Spring源碼分析 - 14-Spring默認重要的組件
- 15、Spring源碼分析 - 15-ConfigurationClassPostProcessor
- 16、Spring源碼分析 - 16-AutowiredAnnotationBeanPostProcessor
- 17、Spring源碼分析 - 17-RequiredAnnotationBeanPostProcessor
- 18、Spring源碼分析 - 18-CommonAnnotationBeanPostProcessor
- 19、Spring源碼分析 - 19-ConfigurationClassPostProcessor
- 20、Spring源碼分析 - 20-Spring事件/監聽器機制
- 21、Spring源碼分析 - 21-Spring AOP概述
- 22、Spring源碼分析 - 22-Spring AOP的實現原理之ProxyFactoryBean
- 23、Spring源碼分析 - 23-TargetSource目標源
- 24、Spring源碼分析 - 24-基于注解@Aspect的AOP實現
- 25、Spring源碼分析 - 25-Spring異步實現原理
- 26、Spring源碼分析 - 26-TaskExecutor與TaskScheduler
- 27、Spring源碼分析 - 27-基于注解@Scheduled定時任務實現
- 28、Spring源碼分析 - 28-Spring緩存原理詳解
- 29、Spring源碼分析 - 29-JdbcTemplat的設計與實現
- 30、Spring源碼分析 - 30-Spring編程式事物的設計與實現
- 31、Spring源碼分析 - 31-Spring聲明式事物的設計與實現
- 32、Spring源碼分析 - 32-基于注解@Transactional的事物實現
- 33、Spring源碼分析 - 32-基于注解@Transactional的事物實現
- 34、Spring源碼分析 - 34-Spring Bean作用域的設計與實現
- 35、Spring源碼分析 - 35-Spring MVC設計原理
- 36、Spring源碼分析 - 36-Spring MVC參數值的綁定
- 37、Spring源碼分析 - 37-Spring MVC的異常處理
- 38、Spring源碼分析 - 38-RestTemplate詳解
- 39、Spring源碼分析 - 39-Spring容器生命周期回調接口LifeCycle
- 40、Spring源碼分析 - 40-Spring Validation參數校驗的使用與原理
- 41、Spring源碼分析 - 41-ClassPathBeanDefinitionScanner
- 42、Spring源碼分析 - 42-@Conditional詳解
真實案例比較
在實際開發中,我們通常會遇到以下幾種情況:
- 簡單的CRUD操作:通常不需要動態代理。
- 復雜的業務邏輯:涉及事務、安全性檢查時,動態代理非常有用。
- 高性能要求的場景:在這種場景下,過度使用動態代理
最后說一句(求關注,求贊,別白嫖我)
最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進大廠原來沒那么難。
這是大佬寫的, 7701頁的BAT大佬寫的刷題筆記,讓我offer拿到手軟
項目文檔&視頻:
項目文檔 & 視頻
本文,已收錄于,我的技術網站 ddkk.com,有大廠完整面經,工作技術,架構師成長之路,等經驗分享
求一鍵三連:點贊、分享、收藏
點贊對我真的非常重要!在線求贊,加個關注我會非常感激