Spring的事務管理是使用AOP(面向切面程式設計)代理的原理來實現的。
Spring事務管理與AOP代理原理
-
AOP代理的作用:
- 在Spring中,AOP代理用於在目標物件的方法執行前後注入自定義的邏輯,這些邏輯通常與業務邏輯無關,但需要在業務邏輯執行時同步執行,如事務管理、日誌記錄、效能檢測等。
- 透過AOP代理,可以將這些橫切關注點(cross-cutting concerns)從核心業務邏輯中分離出來,使得業務邏輯更加清晰和模組化。
-
AOP代理的實現方式:
- Spring AOP主要使用了兩種動態代理方式:JDK動態代理和CGLIB動態代理。
- 如果目標物件實現介面,Spring預設使用JDK動態代理。JDK動態代理是基於介面的代理,透過反射機制生成一個實現了目標物件介面的代理類。
- 如果目標物件沒有實現介面,Spring使用CGLIB動態代理。CGLIB代理是基於類代理,透過操作位元組碼生成目標物件的子類,並重寫其中的方法。
-
事務管理的實現:
- 當為某個Bean配置事務管理時,Spring會為其建立一個代理物件。
- 當呼叫該Bean的某個方法時,實際上是呼叫生成的代理物件的方法。
- 代理物件會在方法執行前後注入事務管理的邏輯,如開啟事務、提交事務、回滾事務等。
為什麼要建立代理物件?
- 實現AOP功能:代理物件是實現AOP功能的關鍵。透過代理物件,可以在目標物件的方法執行前後注入自定義的邏輯,從而實現橫切關注點的分離。
- 控制目標物件的訪問:代理物件還可以提供額外的訪問控制,如許可權控制、引數校驗等。
Spring的單例模式
-
預設單例模式:
- Spring容器預設會將所有的Bean都設定為單例模式。這意味著在Spring容器的整個生命週期中,每個Bean只會被建立一次,並且每次獲取該Bean時都會返回同一個例項。
- 單例模式有助於減少記憶體佔用和提高效能,因為多個元件可以共享同一個Bean例項。
-
如何設定單例模式:
- 在Spring中,可以透過註解(如
@Component
、@Bean
等)或XML配置來顯式地設定Bean的作用域為單例。但通常情況下,無需額外配置,因為單例模式是Spring的預設行為。
- 在Spring中,可以透過註解(如
-
單例模式的注意事項:
- 在併發環境下,單例模式可能會引發執行緒安全問題。因此,在Bean類中需要採用同步機制或使用執行緒安全的物件來確保執行緒安全。
- 單例模式可能會增加耦合性,因為多個元件共享同一個Bean例項。因此,在應用設計中需要慎重考慮是否真正需要使用單例模式。
Spring的事務管理是透過AOP代理來實現的,代理物件的建立是為了實現AOP功能和控制目標物件的訪問。同時,Spring容器預設會將所有的Bean設定為單例模式,以提高效能和減少記憶體佔用。
重點理解:在Spring框架中,當為某個Bean配置事務管理時,Spring確實會為其建立一個代理物件以及目標物件。這兩個物件的銷燬時機取決於Spring容器的生命週期管理和Bean的作用域設定。
代理物件的銷燬時機
代理物件的銷燬時機通常與Spring容器的生命週期相關,具體取決於代理物件的作用域設定:
-
單例作用域(Singleton):
- 當代理物件被配置為單例作用域時,它的生命週期與Spring容器的生命週期一致。
- 在Spring容器關閉時,會觸發代理物件的銷燬方法。此時,Spring容器會呼叫代理物件實現的
DisposableBean
介面的destroy
方法(如果代理物件實現了該介面),或者呼叫在配置檔案中透過destroy-method
屬性指定的銷燬方法。
-
原型作用域(Prototype):
- 當代理物件被配置為原型作用域時,每次獲取代理物件時都會建立一個新的例項。
- 代理物件例項的銷燬不是由Spring容器管理的,而是由使用它們的程式碼來管理的。通常,這些例項會在不再被使用時被垃圾回收器回收。
-
其他作用域:
- 對於會話作用域(Session Scope)、執行緒作用域(Thread Scope)和請求作用域(Request Scope)的代理物件,它們的生命週期分別與會話、執行緒和請求的生命週期一致。
- 當會話結束、執行緒結束或請求結束時,會觸發代理物件的銷燬方法。
目標物件的銷燬時機
目標物件的銷燬時機也取決於其作用域設定,但通常與代理物件的銷燬時機相關聯:
-
如果目標物件也是單例作用域:
- 當Spring容器關閉時,會同時銷燬代理物件和目標物件。
-
如果目標物件是原型作用域或其他作用域:
- 目標物件的銷燬時機將根據其作用域設定來確定,可能與代理物件的銷燬時機不同。
- 例如,如果目標物件是原型作用域,則每次獲取目標物件時都會建立一個新的例項,並且這些例項的銷燬將由使用它們的程式碼來管理。
需要注意的是,Spring容器的關閉通常發生在應用程式關閉時。在Spring Boot應用中,Spring容器會在應用程式退出時自動關閉。如果希望在應用程式執行期間手動關閉Spring容器,可以使用ConfigurableApplicationContext
介面的close
方法來關閉容器。
所以代理物件和目標物件的銷燬時機取決於Spring容器的生命週期管理和Bean的作用域設定。在應用程式關閉時、目標物件或代理物件的作用域結束時,或者代理物件例項不再被使用時,這些物件可能會被銷燬。