若是說 Java 工程師,有什麼必定要「死磕」拿下的東西,那必定是 Spring 無疑了。衆所周知,Spring 不管在 Java 生態系統,仍是在就業市場, Spring Boot、Spring Framework、Spring Data、Spring Cloud、Spring Security、Spring Session等都是Spring Framework 的基石,面試出鏡率之高,無出其右。程序員
先分享一個Spring知識點思惟導圖給你們面試
單例模式:Spring 中的 Bean 默認狀況下都是單例的。無需多說。spring
工廠模式:工廠模式主要是經過 BeanFactory 和 ApplicationContext 來生產 Bean 對象。數據庫
代理模式:最多見的 AOP 的實現方式就是經過代理來實現,Spring主要是使用 JDK 動態代理和 CGLIB 代理。編程
模板方法模式:主要是一些對數據庫操做的類用到,好比 JdbcTemplate、JpaTemplate,由於查詢數據庫的創建鏈接、執行查詢、關閉鏈接幾個過程,很是適用於模板方法。設計模式
IOC 叫作控制反轉,指的是經過Spring來管理對象的建立、配置和生命週期,這樣至關於把控制權交給了Spring,不須要人工來管理對象之間複雜的依賴關係,這樣作的好處就是解耦。在Spring裏面,主要提供了 BeanFactory 和 ApplicationContext 兩種 IOC 容器,經過他們來實現對 Bean 的管理。緩存
AOP 叫作面向切面編程,他是一個編程範式,目的就是提升代碼的模塊性。Srping AOP 基於動態代理的方式實現,若是是實現了接口的話就會使用 JDK 動態代理,反之則使用 CGLIB 代理,Spring中 AOP 的應用主要體如今 事務、日誌、異常處理等方面,經過在代碼的先後作一些加強處理,能夠實現對業務邏輯的隔離,提升代碼的模塊化能力,同時也是解耦。Spring主要提供了 Aspect 切面、JoinPoint 鏈接點、PointCut 切入點、Advice 加強等實現方式。多線程
JDK 動態代理主要是針對類實現了某個接口,AOP 則會使用 JDK 動態代理。他基於反射的機制實現,生成一個實現一樣接口的一個代理類,而後經過重寫方法的方式,實現對代碼的加強。框架
而若是某個類沒有實現接口,AOP 則會使用 CGLIB 代理。他的底層原理是基於 asm 第三方框架,經過修改字節碼生成成成一個子類,而後重寫父類的方法,實現對代碼的加強。模塊化
Spring AOP 基於動態代理實現,屬於運行時加強。
AspectJ 則屬於編譯時加強,主要有3種方式:
編譯時織入:指的是加強的代碼和源代碼咱們都有,直接使用 AspectJ 編譯器編譯就好了,編譯以後生成一個新的類,他也會做爲一個正常的 Java 類裝載到JVM。
編譯後織入:指的是代碼已經被編譯成 class 文件或者已經打成 jar 包,這時候要加強的話,就是編譯後織入,好比你依賴了第三方的類庫,又想對他加強的話,就能夠經過這種方式。
總結下來的話,就是 Spring AOP 只能在運行時織入,不須要單獨編譯,性能相比 AspectJ 編譯織入的方式慢,而 AspectJ 只支持編譯先後和類加載時織入,性能更好,功能更增強大。
BeanFactory 是 Bean 的工廠, ApplicationContext 的父類,IOC 容器的核心,負責生產和管理 Bean 對象。
FactoryBean 是 Bean,能夠經過實現 FactoryBean 接口定製實例化 Bean 的邏輯,經過代理一個Bean對象,對方法先後作一些操做。
SpringBean 生命週期簡單歸納爲4個階段:
實例化,建立一個Bean對象
填充屬性,爲屬性賦值
初始化
若是實現了xxxAware接口,經過不一樣類型的Aware接口拿到Spring容器的資源
若是實現了BeanPostProcessor接口,則會回調該接口的postProcessBeforeInitialzation和postProcessAfterInitialization方法
若是配置了init-method方法,則會執行init-method配置的方法
容器關閉後,若是Bean實現了DisposableBean接口,則會回調該接口的destroy方法
若是配置了destroy-method方法,則會執行destroy-method配置的方法
首先,Spring 解決循環依賴有兩個前提條件:
不全是構造器方式的循環依賴
必須是單例
基於上面的問題,咱們知道Bean的生命週期,本質上解決循環依賴的問題就是三級緩存,經過三級緩存提早拿到未初始化的對象。
第一級緩存:用來保存實例化、初始化都完成的對象
第二級緩存:用來保存實例化完成,可是未初始化完成的對象
第三級緩存:用來保存一個對象工廠,提供一個匿名內部類,用於建立二級緩存中的對象
假設一個簡單的循環依賴場景,A、B互相依賴。
A對象的建立過程:
A注入屬性時,發現依賴B,轉而去實例化B
一樣建立對象B,注入屬性時發現依賴A,一次從一級到三級緩存查詢A,從三級緩存經過對象工廠拿到A,把A放入二級緩存,同時刪除三級緩存中的A,此時,B已經實例化而且初始化完成,把B放入一級緩存。
接着繼續建立A,順利從一級緩存拿到實例化且初始化完成的B對象,A對象建立也完成,刪除二級緩存中的A,同時把A放入一級緩存
最後,一級緩存中保存着實例化、初始化都完成的A、B對象
所以,因爲把實例化和初始化的流程分開了,因此若是都是用構造器的話,就無法分離這個操做,因此都是構造器的話就沒法解決循環依賴的問題了。
不能夠,主要是爲了生成代理對象。
由於三級緩存中放的是生成具體對象的匿名內部類,他能夠生成代理對象,也能夠是普通的實例對象。
使用三級緩存主要是爲了保證無論何時使用的都是一個對象。
假設只有二級緩存的狀況,往二級緩存中放的顯示一個普通的Bean對象,BeanPostProcessor去生成代理對象以後,覆蓋掉二級緩存中的普通Bean對象,那麼多線程環境下可能取到的對象就不一致了。
PROPAGATION_REQUIRED:若是當前沒有事務,就建立一個新事務,若是當前存在事務,就加入該事務,這也是一般咱們的默認選擇。
PROPAGATION_REQUIRES_NEW:建立新事務,不管當前存不存在事務,都建立新事務。
PROPAGATION_NESTED:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則按REQUIRED屬性執行。
PROPAGATION_NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER:以非事務方式執行,若是當前存在事務,則拋出異常。
PROPAGATION_MANDATORY:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就拋出異常。
PROPAGATION_SUPPORTS:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就以非事務執行。‘
這個流程,網上一搜基本都是這張圖了,我也不想再畫一遍了。那其實主要的流程就幾個步驟:
準備環境,根據不一樣的環境建立不一樣的Environment
準備、加載上下文,爲不一樣的環境選擇不一樣的Spring Context,而後加載資源,配置Bean
初始化,這個階段刷新Spring Context,啓動應用
最後結束流程
最後給你們分享
Spring系列的學習筆記和麪試題,包含spring面試題、spring cloud面試題、spring boot面試題、spring教程筆記、spring boot教程筆記、最新阿里巴巴開發手冊(63頁PDF總結)、2020年Java面試手冊。一共整理了1184頁PDF文檔。
關注公衆號:程序員白楠楠, 便可獲取這份1184頁PDF文檔的spring全家桶資料。