Spring5 源碼分析--引導片

序言

本身喜歡將看過的東西寫成博客,一是方便本身查看,二也能夠提供他人蔘考。由於這段時間比較空閒,藉此機會研究Spring源碼,旨在培養習慣、提高本身,但畢竟是一家之言,若是有不對的地方或者建議,歡迎拍磚。git

爲何研究Spring源碼

本身研究源碼的初心就是想看看那些牛逼的框架究竟是有多牛逼,代碼到底有多優雅,怎麼利用設計模式去構建程序,如何漂亮實現解耦,如何設計擴展點靈活讓第三方開發者干預框架的運行,如何與框架進行整合。說出來可能有人還不信,我的並非由於想去BAT這些大廠而研究源碼,估計像我這個年齡別人也不會要了。。。自嘲一下!github

但願本身經過閱讀Spring源碼提升以下能力:設計模式

1.首先確定是閱讀源代碼的能力,找到閱讀源碼的基本方法,提升DEBUG的能力,增強如何定位問題的技巧閉包

2.讓本身內心的大象邁出一小步,讓本身熟悉閱讀源碼,培養習慣,之後看更多的源碼框架

3.從源碼中找到寫出漂亮代碼的底層邏輯,好比設計模式、如何解耦、優雅的語法或者API、很是棒的工具類工具

4.提升項目腳手架質量,提高編碼能力,加快BUG定位速度源碼分析

5.將閱讀源碼的結果分享出來,儘可能可讓路過的人能夠產生閱讀源碼的興趣,解決工做中遇到問題學習

構建Spring源碼

最新的Spring源碼是經過Gradle構建的,所以只接觸過Maven構建的朋友建議花幾個小時在網上找一個Gradle的學習視頻,大概瞭解一下grovvy和Gradle相關知識,否則真的看不懂gradle.build文件。好比閉包、Gradle特有的API等,還有Gradle的安裝、IDEA如何提高Gradle編譯速度等。gradle

基於本身的環境寫了一篇博客:http://www.javashuo.com/article/p-vfbhnoop-ch.html 歡迎參考ui

準備工做

1.簡單學習grovvy和Gradle相關知識

2.瞭解一下設計模式,好比裝飾者、模板方法、工廠方法,還有抽象類、接口的運用,裏面用了大量的設計模式,不提早了解一下,代碼看起來比較吃力

3.學習Java8的Lamda表達式

4.學習Idea的快捷鍵,DEBUG的一些技巧

如何去看Spring源碼

等Spring源碼構建完成後,該如何着手去看喃,固然是寫一個工程,經過DEBUG Spring源碼看執行過程等,總結本身看源碼幾點經驗

1.必定要從GIT上下載源碼並構建,反編譯看源碼,特別是複雜的代碼會發蒙的。

2.在工程中開啓新的工程或者module,引用項目中的module進行調試

3.看源碼以前必定要對框架的使用比較熟悉,千萬不要對框架的使用都不熟悉就跑去看源碼,那樣必定會發蒙的。因此花點錢買點框架使用的書或者視頻先看看,不要吝嗇那幾分錢,等你看完工資必定會漲的。好比SpringMVC,你就只知道加@Controller @Service @Component完成業務代碼可不行。

4.看源碼時經過DEBUG對框架有整體上的認識,不要一來就往深、細了摳,若是那樣的話,你會發現本身很快就看不下去了

5.DEBUG時着重先關注每行代碼執行完後關鍵變量的變化,好比Spring源碼當中的beanDefinitionMap singletonObjects beanPostProcessors等,返回的對象或者值是否是可能你須要關注的

6.善用DEBUG的條件斷點,不然可能你按了無數次F6也到不了你關注的觸發點或者執行點

7.必定要邊看邊加註釋、作筆記、畫圖什麼的,由於一兩天你是看不完的,極可能由於其餘事情耽擱了,等下次來看又蒙了

8.GOOGLE 百度是經常使用工具,也能夠試着搜索一下gitee或者github上面是否已經有別人看過的源碼分析的項目,DOWN下來接着看,能夠提升閱讀速度,可是必定要寫代碼去驗證,由於有人直接翻譯的英文,也許那並無什麼Luan用。既然是看源碼,是基本的東西,凡是別人的東西必定要多方面驗證才能吸取成正確的本身的,不然看了半天結果是錯的就麻煩了。我就遇到了這樣的問題,在搜索引擎上找到的內容其實在Spring5已經變了。

Spring大概的工做流程

開始王婆賣瓜。。。。由於如今開發都是基於註解的,所以也是拿AnnotationConfigApplicationContext做爲分析對象

概要流程

很是概要的圖描述Spring容器初始化過程

 

Spring核心類實例化

    核心類起的做用就好像汽車的發動機,沒它都跑不了咯,還能期望它帶你去撩妹、看帥哥麼。一樣,Spring的核心類可以保證容器或者叫上下文可以正常工做,基於它管理咱們的業務對象,實現業務邏輯,好比:

    AnnotationConfigApplicationContext:也就是Spring的整個容器,Spring還有另一個相似的叫ClassPathXmlApplicatonContext(基於XML配置的),在它裏面包含了全部實例化的單例Bean、系統參數與配置文件加載後的鍵值對、後置處理器、每一個Bean的定義等等

    AnnotatedBeanDefinitionReader:負責讀取被註解修飾了的Bean的定義,並添加到某一個Bean定義的集合當中。典型的場景就是個人ImportResourceAppConfig.class傳入到AnnotatedBeanDefinitionReader.register()方法中,在BeanDefinitionMap中會新增一個對應的元素。

    DefaultListableBeanFactory:這個就至關至關重要了。。。它包含了註冊BeanDefinition-registerBeanDefinition(),而後利用BeanDefinition獲取或者建立Bean的邏輯-getBean(),對應的就有兩個方法常使用的四個變量:

        private final Map<String, BeanDefinition> beanDefinitionMap;--存放全部的Spring Bean定義(BeanDefinition),關於BeanDefinition詳解查看:http://www.javashuo.com/article/p-tqmnjqch-p.html

        private final Map<String, Object> singletonObjects                    --存放全部的單例Spring Bean

        private final Map<String, Object> earlySingletonObjects            --存放循環依賴時須要提早被暴露的Bean,這些Bean並無被不少PostProcessor(中文翻譯爲後置處理器)處理,以解決循環依賴不會出現無限制的遞歸(這裏沒明白不要緊,知道它和解決循環依賴有很重要關係便可,後面會詳細說明)

        private final Set<String> singletonsCurrentlyInCreation              --存放當前容器中正在被建立的beanName(它也和循環依賴有很大關係)

核心組件類定義的註冊

    圖中的就是Bean定義集合的元素截圖,這些組件會完成@ComponentScan註解的包掃描,以及被掃描到的類定義註冊,實例化裸對象,完成SpringBean的初始化(包含了各類PostProcessor的處理,好比依賴注入)

    圖中截圖Map中Key對應的類以下順序:

    ConfigurationClassPostProcessor:掃描@ComponentScan中指定包路徑下全部符合Spring規則的類,如加了@Configuration @Component等的類,將他們的BeanDefinition註冊到beanDefinitionMaps當中。還有另一個功能就是添加一個ImportAwareBeanPostProcessor,它可讓你的Bean獲取到將@Import做爲元註解時自定義註解的屬性鍵值對(此功能能夠先無論)

    DefaultEventListenerFactory:和Application Event有關,還沒詳細查看之後再補充

    EventListenerMethodProcessor:和Application Event有關,還沒詳細查看之後再補充

    AutowiredAnnotationBeanPostProcessor:負責依賴注入和屬性注入,好比@Autowired @Value的相應動做

    CommonAnnotationBeanPostProcessor:負責JSR250相關注解的解析與執行,好比@PostContruct @Resource等

註冊配置類

    使用AnnotatedBeanDefinitionReader.register(ImportResourceAppConfig.class)ImportResourceAppConfig的BeanDefinition註冊到beanDefinitionMaps當中。完成這個動做以後Spring才能拿到配置類作下一步的包掃描、依賴注入等操做

解析配置類上的註解,並完成BeanDefinition註冊

   主要就是ConfigurationClassPostProcessor和AutowiredAnnotationBeanPostProcessor兩個類啓核心做用(固然還有這兩個牽扯出來的其餘類),好比ConfigurationClassPostProcessor.ConfigurationClassPaser就是負責完成包掃描的,包含了@ComponentScan @Component @Import @ImportResource @Bean 註解的解析完成全部的BeanDefinition的建立並註冊到beanDefinitionMaps當中

根據BeanDefinition實例化Spring Bean

    上一步已經將全部的BeanDefinition準備好,接下來就是遍歷他們,使用動態代理完成對象的實例化,並最終獲得Spring Bean(多是裸對象,也多是代理對象)。

總結:簡單的說Spring並非直接根據Class文件建立一個Bean,而是生成對應的BeanDefinition對象,再根據它建立想要的Bean,在這個過程中Spring提供了豐富的擴展點去幹預BeanDefinition狀態和Bean的狀態,這些擴展點就是Spring真正強大的緣由。

相關文章
相關標籤/搜索