Spring 知識框架
IOC 與 DI
IoC 和DI 其實是同一個概念的不同角度描述。
什麼是IOC?
沒有IOC 之前:我們需要一個物件,都是我們自己去new 一個依賴物件。 有了IOC 之後: 我們將建立物件的權益交給了IOC 容器,由容器來控制物件的建立和生命週期。物件只是被動的接受依賴物件。
為什麼需要IOC?IOC 的好處?
控制反轉其實是一種設計思想。沒有控制反轉,我們需要一個物件,我們就自己去NEW ,導致程式碼之間的高度耦合。有了控制反轉,由容器來控制物件的依賴注入,程式碼之間鬆散耦合。
IOC 原始碼跟讀
IOC 和DI 主要是通過反射機制完成的。
@Override
public void refresh() throws BeansException,IllegalStateException {
// 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛
synchronized (this.startupShutdownMonitor) {
// 準備工作
// 1、記錄下容器的啟動時間
// 2、標記“已啟動”狀態
// 3、處理配置檔案中的佔位符
prepareRefresh();
// 生成BeanFactory
// 1、生成 BeanFactory
// 2、解析配置檔案,生成BeanDefinition, 註冊到BeanFactory
// 此時,Bean 還未初始化,只是配置資訊提取出來了。BeanDefinition 的儲存格式
// beanName-> beanDefinition 的 map
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 1、設定 BeanFactory 的類載入器,用於BeanFactory 載入類;
// 2、新增一個 BeanPostProcessor
// 3、對ApplicationContext 繼承的物件進行賦值
// 4、手動註冊幾個特殊的 bean,如environment、systemProperties、systemEnvironment
// 這塊待會會展開說
prepareBeanFactory(beanFactory);
try {
// 【這裡需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現了此介面,
// 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。】
// 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候新增一些特殊的 BeanFactoryPostProcessor 的實現類或做點什麼事
postProcessBeanFactory(beanFactory);
// 呼叫 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 回撥方法
invokeBeanFactoryPostProcessors(beanFactory);
// 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
// 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之後得到執行。這裡僅僅是註冊,之後會看到回撥這兩方法的時機
registerBeanPostProcessors(beanFactory);
// 初始化當前 ApplicationContext 的 MessageSource,國際化這裡就不展開說了,不然沒完沒了了
initMessageSource();
// 初始化當前 ApplicationContext 的事件廣播器,這裡也不展開了
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鉤子方法),不展開說
// 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 註冊事件監聽器,監聽器需要實現 ApplicationListener 介面。這也不是我們的重點,過
registerListeners();
// 重點,重點,重點
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最後,廣播事件,ApplicationContext 初始化完成,不展開
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 銷燬已經初始化的 singleton 的 Beans,以免有些 bean 會一直佔用資源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// 把異常往外拋
throw ex;
}
finally {
// Reset common introspection caches in Spring's core,since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
複製程式碼
參考: yikun.github.io/2015/05/29/… javadoop.com/post/spring…
Bean 的生命週期
載入XML——建立BeanFactory ——讀取Resource —— 解析BeanDefinition ——註冊到BeanFactory ——初始化Bean ——建立Bean 例項 —— 注入Property
AOP
靜態代理、JDK動態代理、CGLIB動態代理。
靜態代理:代理類實現被代理類的介面,同時與被代理類是組合關係。 JDK動態代理:代理類可代理任意類的任意方法,但是,任意類必須要實現某個介面。 CGLIB動態代理:CGlib是一個位元組碼增強庫,為AOP等提供了底層支援。
AOP:即面向切面程式設計,AOP可以分離系統的業務邏輯和系統服務。
參考: www.cnblogs.com/puyangsky/p… juejin.im/post/5aa781…
Spring單例與執行緒安全
懶載入:spring 預設的是非懶載入,即在容器初始化時候初始化;懶載入即使用者向容器第一次索要bean時進行初始化。
spring依賴注入時,使用了雙重判斷加鎖的單例模式。首先從快取中獲取bean例項,如果為null,對快取map加鎖,然後再從快取中獲取bean,如果繼續為null,就建立一個bean。這樣雙重判斷,能夠避免在加鎖的瞬間,有其他依賴注入引發bean例項的建立,從而造成重複建立的結果。
參考: www.cnblogs.com/chengxuyuan…
Spring事務管理
事務隔離級別:
TransactionDefinition.ISOLATION_DEFAULT: 使用後端資料庫預設的隔離級別,Mysql 預設採用的 REPEATABLE_READ隔離級別 Oracle 預設採用的 READ_COMMITTED隔離級別. TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔離級別,允許讀取尚未提交的資料變更,可能會導致髒讀、幻讀或不可重複讀 TransactionDefinition.ISOLATION_READ_COMMITTED: 允許讀取併發事務已經提交的資料,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生 TransactionDefinition.ISOLATION_REPEATABLE_READ: 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生。 TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生幹擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程式的效能。通常情況下也不會用到該級別。
事務傳播行為:
支援當前事務的情況:
TransactionDefinition.PROPAGATION_REQUIRED: 如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。 TransactionDefinition.PROPAGATION_SUPPORTS: 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。 TransactionDefinition.PROPAGATION_MANDATORY: 如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。(mandatory:強制性)
不支援當前事務的情況:
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 建立一個新的事務,如果當前存在事務,則把當前事務掛起。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式執行,如果當前存在事務,則把當前事務掛起。 TransactionDefinition.PROPAGATION_NEVER: 以非事務方式執行,如果當前存在事務,則丟擲異常。
其他情況:
TransactionDefinition.PROPAGATION_NESTED: 如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
實現宣告式事務的四種方式:
1、基於 TransactionInterceptor 的宣告式事務: Spring 宣告式事務的基礎,通常也不建議使用這種方式,但是與前面一樣,瞭解這種方式對理解 Spring 宣告式事務有很大作用。
2、基於 TransactionProxyFactoryBean 的宣告式事務: 第一種方式的改進版本,簡化的配置檔案的書寫,這是 Spring 早期推薦的宣告式事務管理方式,但是在 Spring 2.0 中已經不推薦了。
3、基於< tx> 和< aop>名稱空間的宣告式事務管理: 目前推薦的方式,其最大特點是與 Spring AOP 結合緊密,可以充分利用切點表示式的強大支援,使得管理事務更加靈活。
4、基於 @Transactional 的全註解方式: 將宣告式事務管理簡化到了極致。開發人員只需在配置檔案中加上一行啟用相關後處理 Bean 的配置,然後在需要實施事務管理的方法或者類上使用 @Transactional 指定事務規則即可實現事務管理,而且功能也不必其他方式遜色。