類與類之間的依賴關系形成了閉環,就會導致循環依賴問題的產生。
比如下圖中A類依賴了B類,B類依賴了C類,而最后C類又依賴了A類,這樣就形成了循環依賴問題。
1.通過構造方法進行依賴注入時產生的循環依賴問題。
該情況會報異常,在new對象的時候就會堵塞住了,其實也就是”先有雞還是先有蛋“的歷史難題。
2.通過setter方法進行依賴注入且是在多例模式下產生的循環依賴問題。
該情況會報異常,每一次getBean()時,都會產生一個新的Bean,如此反復下去就會有無窮無盡的Bean產生了,最終就會導致OOM問題的出現。
3.通過setter方法進行依賴注入且是在單例模式下產生的循環依賴問題。
因此在Spring中,前兩種都會報異常,只有第(3)種方式的循環依賴問題能被解決。
Spring在單例模式下的setter方法依賴注入引起的循環依賴問題,主要是通過二級緩存和三級緩存來解決的,其中三級緩存是主要功臣。解決的核心原理就是:在對象實例化之后,依賴注入之前,Spring提前暴露的Bean實例的引用在第三級緩存中進行存儲。
Spring中有三個緩存,用于存儲單例的Bean實例,這三個緩存是彼此互斥的,不會針對同一個Bean的實例同時存儲。如果調用getBean,則需要從三個緩存中依次獲取指定的Bean實例。 讀取順序依次是一級緩存 ==> 二級緩存 ==> 三級緩存。
Spring啟動過程是IOC容器的啟動過程,本質是創建和初始化bean工廠(BeanFactory).BeanFactory是Spring IOC的核心,Spring使用beanFactory來實例化,配置和管理bean。對于web程序,IOC容器啟動過程即是建立上下文的過程,web容器會提供一個全局的servletContext上下文環境。其啟動過程主要包含三個類,ContextLoaderListener,ContextLoader和XmlWebApplicationContext。
在web.xml中提供ContextLoaderListener上下文監聽器,在web容器啟動時,會觸發容器初始化事件,ContextLoaderListener會監聽到這個事件,從而觸發ContextInitialized方法完成上下文初始化,這個方法中調用父類ContextLoader的方法完成上下文初始化。ContextLoader類中主要完成三件事:
1)創建WebApplicationContext;
2)加載對應的Spring配置文件中的bean;(refresh方法,完成bean的加載)
3)將WebApplicationContext放入servletContext中。ContextLoaderListener監聽器初始化完之后,開始初始化web.xml中配置的servlet,如DispatcherSevlet
ContextLoaderListener監聽器監聽的是servletContext,當web容器初始化后,servletContext發生變化時,會觸發相應事件。
Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是無法提供事務功能的。Spring只提供統一事務管理接口,具體實現都是由各數據庫自己實現,數據庫事務的提交和回滾是通過 redo log 和 undo log實現的。Spring會在事務開始時,根據當前環境中設置的隔離級別,調整數據庫隔離級別,由此保持一致。
①編程式事務管理使用TransactionTemplate。
②聲明式事務管理建立在AOP之上的。其本質是通過AOP功能,對方法前后進行攔截,將事務處理的功能編織到攔截的方法中,也就是在目標方法開始之前啟動一個事務,在執行完目標方法之后根據執行情況提交或者回滾事務。
聲明式事務最大的優點就是不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明或通過@Transactional注解的方式,便可以將事務規則應用到業務邏輯中,減少業務代碼的污染。唯一不足地方是,最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別。
Spring事務的傳播機制說的是,當多個事務同時存在的時候,Spring如何處理這些事務的行為。事務傳播機制實際上是使用簡單的ThreadLocal實現的,所以,如果調用的方法是在新線程調用的,事務傳播實際上是會失效的。① PROPAGATION_REQUIRED:(默認傳播行為)如果當前沒有事務,就創建一個新事務;如果當前存在事務,就加入該事務。
② PROPAGATION_REQUIRES_NEW:無論當前存不存在事務,都創建新事務進行執行。
③ PROPAGATION_SUPPORTS:如果當前存在事務,就加入該事務;如果當前不存在事務,就以非事務執行。‘
④ PROPAGATION_NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
⑤ PROPAGATION_NESTED:如果當前存在事務,則在嵌套事務內執行;如果當前沒有事務,則按REQUIRED屬性執行。
⑥ PROPAGATION_MANDATORY:如果當前存在事務,就加入該事務;如果當前不存在事務,就拋出異常。
⑦ PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則拋出異常。
① ISOLATION_DEFAULT:這是個 PlatfromTransactionManager 默認的隔離級別,使用數據庫默認的事務隔離級別。
② ISOLATION_READ_UNCOMMITTED:讀未提交,允許事務在執行過程中,讀取其他事務未提交的數據。
③ ISOLATION_READ_COMMITTED:讀已提交,允許事務在執行過程中,讀取其他事務已經提交的數據。
④ ISOLATION_REPEATABLE_READ:可重復讀,在同一個事務內,任意時刻的查詢結果都是一致的。
⑤ ISOLATION_SERIALIZABLE:所有事務逐個依次執行。
1. @Transactional配置的方法非public權限修飾(例如private的就別加了);
2. @Transactional所在類非Spring容器管理的bean(例如一個Util就別加了,都沒注入容器,你叫Spring怎么用他的AOP幫你管理事務?);
3. @Transactional所在類中,注解修飾的方法被類內部方法調用(例如同一個class類中,方法A調用方法B,只在方法B加了@Transactional注解,那就失效了);
4. 業務代碼拋出異常類型非RuntimeException,事務失效;
5. 業務代碼中存在異常時,使用try…catch…語句塊捕獲,而catch語句塊沒有throw new RuntimeExecption異常(只有該異?;蛘咚母府惓@鏓xception可以回滾);
6. 注解@Transactional中Propagation屬性值設置錯誤(例如Propagation.NOT_SUPPORTED,一般不會這么設置)
7. mysql關系型數據庫,且存儲引擎是MyISAM而非InnoDB,則事務會不起作用。
在java中異常的基類為Throwable,Error和Exception繼承Throwable。Exception中RuntimeException及其子類成為未檢查異常(unchecked),其它Exception成為已檢查異常(checked)。
Spring的事務管理默認是針對unchecked exception回滾,也就是默認對Error異常和RuntimeException異常以及其子類進行事務回滾,且必須拋出異常,若使用try-catch對其異常捕獲則不會進行回滾?。‥rror異常和RuntimeException異常拋出時不需要方法調用throws或try-catch語句);
checked異常,checked異常必須由try-catch語句包含或者由方法throws拋出,且事務默認對checked異常不進行回滾。