閱讀422 返回首頁    go 小米 go 小米6


Spring 設計理念探討係列一

        一直想寫這麼一篇文章,來總結一下近幾年來自己對Spring的理解(包括源碼賞析,模式挖掘, 擴展實踐等)。最近在做一個多級反饋隊列的設計,剛好是構建在Spring之上。趁此機會寫下這篇文章,希望大家多提寶貴意見。同時,為了不落俗套(分析Spring源碼的文章已經泛濫了,但大多至於流程推敲,蘊含在其中的設計哲學往往少有人問津),這裏采用正反推演的方法進行分析,目的很明確,將其中蘊含的設計理念一一“拖”出來.為我所用~

         撇開Spring的源碼先不談。我們先來談談如何精進一門技藝的問題。自己有個習慣,在學習某門技術前,先去官方看一下其Introduce,了解該技術產生的背景。當然對於文檔比較棒的開源項目,我們還可以了解到跟多的信息(比方說其其適用場景等)。其實也就間接地告訴我們了它的優缺點。有了這些大致了解後,接下來要做的就是從Demo入手,先內部勾勒出它的設計思路(如何做?拿張紙畫下來,異或?),然後翻開源碼,從大處著手,逐步深挖。很多同學都說,自己學習一門新技術後,過一陣子就忘了?why?不妨使用上麵的思路。當然,我們也不可忽視個人的技術敏感性在其中發揮了不小的作用。ok,這裏給出一種思路,希望能對大家學習開源項目有些許幫助。

         好,進入我們的主題吧~Spring的 IOC和AOP兩個核心概念,想必大家都很熟悉了。IOC將控製權從關聯依賴對象的生命周期中解放出來,放到容器中(等等,什麼是容器?容器的作用是什麼?這個你有想過嗎?),進而實現對其生命周期的控製。凡事適度即可,工作中看到很多IOC被濫用,導致可測性、可維護性降低的case不在少數。這裏需要引起大家的重視。好,下麵我們簡單回憶一下Spring IOC容器控製Bean的第一個階段,即Bean的(注意,Spring中的Bean概念上更趨近於Eric Evans提到的領域模型.其中蘊含了倉儲,聚合根,領域服務等核心理念。其實大家大可以不用理會這麼多概念,想想看,其實這些都隻是指導我們進行OOD的一些思考,更多的是一種架構模式)的定位,裝載,解析,注冊。

         這裏,我們要從spring的頂級容器BeanFactory說起,瞧瞧它的名字,落腳點是Factory,那麼我們可以拍著大腿想一想,這個東西就是用來生產Bean的,對吧.別急著深入,我們再來看另外一個容易混淆的概念,FactoryBean,落腳點是Bean,看到了吧,我前麵說過,bean是spring的領域對象,factory納入到容器管理後,就對應了一個FactoryBean.好,我們回到BeanFactory上來,首先我們簡單回憶一下它繼承體係上的三個頂級孩子, AutowireCapableBeanFactory, HierarchicalBeanFactory,ListableBeanFactory. AutowireCapableBeanFactory,正如其名,具有自動裝配能力的容器.這裏有一個命名技巧,當你需要的類具有某種能力時,後綴可以綴上able,諸如JDK中常見的 Comparable, Iterable, Adjustable,Callable,Cloneable等或者直接綴上Capable.著重關注一下的是該容器一般很少被我們直接擴展,可以這麼理解,它是容器繼承體係的核心層(想想看,最核心的,也是最通用的,一般用不著你去擴展的吧). HierarchicalBeanFactory,更通俗易懂了,裏麵就兩個擴展方法,可以獲得父類Bean工廠,根據名字判斷bean是否由本BeanFactory裝載. ListableBeanFactory,有列舉該容器下定義的bean的功能.當然,除了getBeanDefinitionCount 和containsBeanDefinition方法外,不推薦大家直接使用該IOC.鳥瞰過後,我們直接深入內部,來看個究竟吧.剛才說了第一階段包括四個核心步驟,bean的定位,拍著大腿想想,讓我們來設計的話,不就是設計一個BeanLoader去搞搞嗎,沒錯,但是bean從哪裏發現呢?IO流?沒錯,這些統統都稱為Resource.我們就先定義一個ResourceLoader類.等等,既然它抽象到resource的層麵了,我們先來看看都有哪些resource吧.我得上圖了,再不上圖,就要挨罵了.

      

好了,通常情況下,我們使用的是ClassPathResource去定位Bean配置文件的.ok,有了資源,我們需要加載了吧,前麵說了,搞個ResourceLoader的東東吧.來看張截圖,在DefaultResourceLoader中有個方法值得我們關注一下,如下圖:


這裏沒什麼好說的,獲取到資源後,我們需要加載它了吧,ok,這個時候,需要BeanDefinitionReader出場了,Spring將Bean的載入交給了這個家夥,先來看看繼承體係吧.



來看看AbstractBeanDefinitionReader是怎麼進行bean的load操作吧.截圖如下,我們隻看loadBeanDefinitions方法的核心部分.


再往下進行之前,先提個問題吧.在使用spring的過程中,我們往往希望對bean配置文件進行歸類,比方說專門用於做基礎建設用的配置(dataSource,transaction,annotation-driven,advisor等),專門的Action層配置,專門的Service層配置,專門的SOA服務接口契約配置,專門的….等等.如果這些文件中有多個bean相同的話,這裏是怎麼處理的呢.等等,在看這個問題前,我們需要注意一下,這裏為了防止資源文件的並發訪問,使用了ThreadLocal,隻不過被Sping簡單包了一個名字,叫NamedThreadLocal,好進入具體的doLoadBeanDefinitions方法,我們來看剛才那個問題的答案.如圖:


等等,我們不是再討論Bean的載入嗎?怎麼調到registerBeanDefinitions,真細心,沒錯這裏已經來到Bean的解析過程了,等等,明明是注冊,你為什麼硬要說是解析呢?spring這裏的處理邏輯比較繞,它是先完成解析,然後才在DefaultListableBeanFactory裏麵完成注冊的.為什麼要解析,我們知道XML的DOM模型並不符合BeanDefinition這個Spring的領域模型,在使用之前,當然需要對DOM->BeanDefinition進行解析適配嘍.上圖:


繼續往裏麵走,這裏實質上的解析是交給一個叫BeanDefinitionParserDelegate的類.等等,在此駐足兩秒鍾先,關注一下preProcessXml和postProcessXml這兩個方法.鉤子函數啊,同誌們~繼續往下走,我們來看一個比較關鍵的入口方法parseBeanDefinitions,如圖:



好,這裏我們隻是簡單提及下Spring的這個擴展點.後麵會有比較詳細的擴展demo,這裏我們還是把主要精力集中在parseDefaultElement方法上吧.


未完,待續...




參考資料:

1. https://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/

2. https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html

3. https://www.ibm.com/developerworks/cn/java/j-cq01307/index.html

4. https://www.openwebx.org/docs/autoconfig.html

5. https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/index.html

最後更新:2017-04-02 06:52:19

  上一篇:go 分享Magento後台Flash形式上傳圖片按鈕的中文版
  下一篇:go AIDL文件中 in類型和out類型數據的區別