Rising Sun

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            148 隨筆 :: 0 文章 :: 22 評論 :: 0 Trackbacks

          本文主要以spring ioc容器基本代碼骨架為切入點,理解ioc容器的基本代碼組件結構,各代碼組件細節剖析將放在后面的學習文章里。

           http://www.iteye.com/topic/1113459

          關于IOC容器

          IoC容器:最主要是完成了完成對象的創建和依賴的管理注入等等。

          先從我們自己設計這樣一個視角來考慮:

          所謂控制反轉,就是把原先我們代碼里面需要實現的對象創建、依賴的代碼,反轉給容器來幫忙實現。那么必然的我們需要創建一個容器,同時需要一種描述來讓容器知道需要創建的對象與對象的關系。這個描述最具體表現就是我們可配置的文件。

          對象和對象關系怎么表示?

          可以用xmlproperties文件等語義化配置文件表示。

          描述對象關系的文件存放在哪里?

          可能是classpathfilesystem,或者是URL網絡資源,servletContext等。

          回到正題,有了配置文件,還需要對配置文件解析。

          不同的配置文件對對象的描述不一樣,如標準的,自定義聲明式的,如何統一? 在內部需要有一個統一的關于對象的定義,所有外部的描述都必須轉化成統一的描述定義。

          如何對不同的配置文件進行解析?需要對不同的配置文件語法,采用不同的解析器。

           

          基于以上問題,對應過來,剛好是 spring ioc 容器抽象的的幾個主要接口:

          Resource

          BeanDefinition

          BeanDefinitionReader

          BeanFactory

          ApplicationContext

          以上五個都是接口,都有各式各樣的實現,正是這5個接口定義了spring ioc容器的基本代碼組件結構。而其組件各種實現的組合關系組成了一個運行時的具體容器。

           

          各代碼組件詳解

          1.Resource

          是對資源的抽象,每一個接口實現類都代表了一種資源類型,如ClasspathResourceURLResourceFileSystemResource等。每一個資源類型都封裝了對某一種特定資源的訪問策略。它是spring資源訪問策略的一個基礎實現,應用在很多場景。

           

           

           

           

          具體可以參考文章:

          Spring 資源訪問剖析和策略模式應用

          http://www.ibm.com/developerworks/cn/java/j-lo-spring-resource/index.html

           

           

          2.BeanDefinition

          用來抽象和描述一個具體bean對象。是描述一個bean對象的基本數據結構。

          3.BeanDefinitionReader

          BeanDefinitionReader將外部資源對象描述的bean定義統一轉化為統一的內部數據結構BeanDefinition。對應不同的描述需要有不同的Reader。如XmlBeanDefinitionReader用來讀取xml描述配置的bean對象。



           

          4.BeanFactory

          用來定義一個很純粹的bean容器。它是一個bean容器的必備結構。同時和外部應用環境等隔離。BeanDefinition是它的基本數據結構。它維護一個BeanDefinitions Map,并可根據BeanDefinition的描述進行bean的創建和管理。



           

          5.ApplicationContext

          從名字來看叫應用上下文,是和應用環境息息相關的。沒錯這個就是我們平時開發中經常直接使用打交道的一個類,應用上下文,或者也叫做spring容器。其實它的基本實現是會持有一個BeanFactory對象,并基于此提供一些包裝和功能擴展。為什么要這么做呢?因為BeanFactory實現了一個容器基本結構和功能,但是與外部環境隔離。那么讀取配置文件,并將配置文件解析成BeanDefinition,然后注冊到BeanFactory的這一個過程的封裝自然就需要ApplicationContextApplicationContext和應用環境細細相關,常見實現有ClasspathXmlApplicationContext,FileSystemXmlApplicationContext,WebApplicationContext等。ClasspathxmlFileSystemWeb等詞都代表了應用和環境相關的一些意思,從字面上不難理解各自代表的含義。

          當然ApplicationContextBeanFactory的區別遠不止于此,有:

          1.  資源訪問功能:在ResourceResourceLoader的基礎上可以靈活的訪問不同的資源。

          2.  支持不同的信息源。

          3.  支持應用事件:繼承了接口ApplicationEventPublisher,這樣在上下文中為bean之間提供了事件機制。

          ……



           

           

          以上5個組件基本代表了ioc容器的一個最基本組成,而組件的組合是放在ApplicationContext的實現這一層來完成。

           

          以ClasspathXmlApplicationContext 容器實現為例,其組合關系如下:

           


          ClassPathXmlApplicationContext的refresh() 方法負責完成了整個容器的初始化。

          為什么叫refresh?也就是說其實是刷新的意思,該IOC容器里面維護了一個單例的BeanFactory,如果bean的配置有修改,也可以直接調用refresh方法,它將銷毀之前的BeanFactory,重新創建一個BeanFactory。所以叫refresh也是能理解的。

          以下是Refresh的基本步驟:
          1.把配置xml文件轉換成resource。resource的轉換是先通過ResourcePatternResolver來解析可識別格式的配置文件的路徑
          (如"classpath*:"等),如果沒有指定格式,默認會按照類路徑的資源來處理。 
          2.利用XmlBeanDefinitionReader完成對xml的解析,將xml Resource里定義的bean對象轉換成統一的BeanDefinition。
          3.將BeanDefinition注冊到BeanFactory,完成對BeanFactory的初始化。BeanFactory里將會維護一個BeanDefinition的Map。

          當getBean的時候就會根據調用BeanFactory,根據bean的BeanDifinition來實例化一個bean。當然根據bean的lazy-init、protetype等屬性設置不同以上過程略有差別。

           

          refresh()代碼如下:

          Java代碼  收藏代碼
          1. public void refresh() throws BeansException, IllegalStateException {  
          2.     synchronized (this.startupShutdownMonitor) {  
          3.         // Prepare this context for refreshing.  
          4.         prepareRefresh();  
          5.   
          6.         // Tell the subclass to refresh the internal bean factory.  
          7.         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
          8.   
          9.         // Prepare the bean factory for use in this context.  
          10.         prepareBeanFactory(beanFactory);  
          11.   
          12.         try {  
          13.             // Allows post-processing of the bean factory in context subclasses.  
          14.             postProcessBeanFactory(beanFactory);  
          15.   
          16.             // Invoke factory processors registered as beans in the context.  
          17.             invokeBeanFactoryPostProcessors(beanFactory);  
          18.   
          19.             // Register bean processors that intercept bean creation.  
          20.             registerBeanPostProcessors(beanFactory);  
          21.   
          22.             // Initialize message source for this context.  
          23.             initMessageSource();  
          24.   
          25.             // Initialize event multicaster for this context.  
          26.             initApplicationEventMulticaster();  
          27.   
          28.             // Initialize other special beans in specific context subclasses.  
          29.             onRefresh();  
          30.   
          31.             // Check for listener beans and register them.  
          32.             registerListeners();  
          33.   
          34.             // Instantiate all remaining (non-lazy-init) singletons.  
          35.             finishBeanFactoryInitialization(beanFactory);  
          36.   
          37.             // Last step: publish corresponding event.  
          38.             finishRefresh();  
          39.         }  
          40.   
          41.         catch (BeansException ex) {  
          42.             // Destroy already created singletons to avoid dangling resources.  
          43.             beanFactory.destroySingletons();  
          44.   
          45.             // Reset 'active' flag.  
          46.             cancelRefresh(ex);  
          47.   
          48.             // Propagate exception to caller.  
          49.             throw ex;  
          50.         }  
          51.     }  
          52. }  

           以上的obtainFreshBeanFactory是很關鍵的一個方法,里面會調用loadBeanDefinition方法,如下:

          Java代碼  收藏代碼
          1. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  
          2.     // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
          3.     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
          4.   
          5.     // Configure the bean definition reader with this context's  
          6.     // resource loading environment.  
          7.     beanDefinitionReader.setResourceLoader(this);  
          8.     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
          9.   
          10.     // Allow a subclass to provide custom initialization of the reader,  
          11.     // then proceed with actually loading the bean definitions.  
          12.     initBeanDefinitionReader(beanDefinitionReader);  
          13.     loadBeanDefinitions(beanDefinitionReader);  
          14. }  

           LoadBeanDifinition方法很關鍵,這里特定于整個IOC容器,實例化了一個XmlBeanDefinitionReader來解析Resource文件。關于Resource文件如何初始化和xml文件如何解析都在

          Java代碼  收藏代碼
          1. loadBeanDefinitions(beanDefinitionReader);  

           里面的層層調用完成,這里不在累述。

          小結 

          Spring的擴展性是毋庸置疑的,學習spring的設計是一個很好的實踐理論結合。主要個人覺得有幾點:

          1.  框架頂層的設計有著很好的抽象,遵循面向接口編程的規范。ResourceBeanFactoryApplicationContext都是非常好的接口抽象,非常明確的定義了該組件的一些功能。

          2.  利用組合模式。

          3.  個組件的實現里大量使用了模板方法模式,提升了同一組件代碼的復用性。

          4.  各種設計保留了擴展的接口,很多基于spring的框架都可以很容易的介入實現了自己的一些擴展。

          5.  框架里采用里很多經典的設計模式,如代理、裝飾、策略等等。

          posted on 2013-02-28 10:46 brock 閱讀(273) 評論(0)  編輯  收藏 所屬分類: 學習總結
          主站蜘蛛池模板: 耒阳市| 吴川市| 平果县| 柏乡县| 永川市| 平阳县| 阜新| 福州市| 新沂市| 洛阳市| 日喀则市| 内丘县| 镇安县| 金秀| 山西省| 保德县| 平顺县| 凌源市| 长治市| 泽普县| 理塘县| 隆昌县| 鱼台县| 宁阳县| 涞水县| 永寿县| 九江市| 玉屏| 津市市| 永吉县| 钟祥市| 固安县| 内乡县| 南川市| 葵青区| 沙河市| 乐平市| 南阳市| 清丰县| 江安县| 阿克苏市|