spring源碼研究
⑴ spring源碼讀完什麼水平
研究框架的源碼:一、前提: 需要基礎很扎實,做過很多項目了之後。二、作用: 1、為了更好的掌握框架 2、更好的處理代碼中出現的問題或者bug
⑵ Spring事件監聽機制源碼解析
1.Spring事件監聽體系包括三個組件:事件、事件監聽器,事件廣播器。
事件:定義事件類型和事件源,需要繼承ApplicationEvent。
事件監聽器:用來監聽某一類的事件,並且執行具體業務邏輯,需要實現ApplicationListener 介面或者需要用@ListenerEvent(T)註解。好比觀察者模式中的觀察者。
事件多播器:負責廣播通知所有監聽器,所有的事件監聽器都注冊在了事件多播器中。好比觀察者模式中的被觀察者。Spring容器默認生成的是同步事件多播器。可以自定義事件多播器,定義為非同步方式。
創建 的過程中,會執行refresh()中的()方法。該方法先獲取bean工廠,然後判斷工廠是否包含了beanName 為 applicationEventMulticaster的bean。如果包含了,則獲取該bean,賦值給applicationEventMulticaster 屬性。如果沒有,則創建一個 對象,並且賦值給 applicationEventMulticaster 。實現了源碼如下:
監聽器的注冊有兩種,通過實現 ApplicationListener介面或者添加@EventListener註解。
注冊的邏輯實現在refresh()中的registerListeners()方法裡面。第一步,先獲取當前ApplicationContext中已經添加的 applicationListeners(SpringMVC源碼中有用到),遍歷添加到多播器中。第二步,獲取實現了ApplicationListener介面的listenerBeanNames集合,添加至多播器中。第三步,判斷是否有早期事件,如果有則發起廣播。
思考一下,上面的代碼中第二步為啥添加的是listenerBeanName?
如果監聽器是懶載入的話(即有@Lazy 註解)。那麼在這個時候創建監聽器顯然是不對的,這個時候不能創建監聽器。所以添加監聽器到多播器的具體邏輯放在初始化具體的監聽器之後。通過 BeanPostProcessor 的介面實現。具體的實現類是 ApplicationListenerDetector 。這個類是在 refreah()中prepareBeanFactory()方法中添加的。代碼如下:
在創建 的構造方法中,會執行org.springframework.context.annotation.AnnotationConfigUtils#(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 方法。這個方法中會添加兩個 beanDefs, 代碼如下:
EventListenerMethodProcessor:事件監聽器的BeanFactory後置處理器,在前期會創建 DefaultEventListenerFactory ,後期在創建好Bean之後,根據 EventListener 屬性,調用DefaultEventListenerFactory創建具體的 。
DefaultEventListenerFactory:監聽器的創建工廠,用來創建 。
EventListenerMethodProcessor 的類繼承圖如下:
在refreash的()中會調用 org.springframework.context.event.EventListenerMethodProcessor#postProcessBeanFactory方法,獲取EventListenerFactory 類型的 Bean。代碼如下:
在 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons 方法中,創建完所有的單例Bean 之後,會遍歷所有Bean是否實現了 SmartInitializingSingleton 介面。如果實現介面會執行該 Bean 的 afterSingletonsInstantiated() 方法。代碼如下:
org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated 中會調用私有方法 processBean()進行 ApplicationEventAdatper 的創建。代碼如下:
可以通過調用 org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType) 方法進行事件的調用。代碼如下:
中的 multicasEvent,invokeListener,doInvokeListener 三個方法代碼如下:
SpringMVC中就是通過Spring的事件機制進行九大組件的初始化。
監聽器定義在FrameworkServlet類中,作為內部類。代碼如下:
監聽器的添加在org.springframework.web.servlet.FrameworkServlet# 中進行。通過SourceFilteringListener進行包裝。添加代碼如下:
在refresh中的registerListeners方法進行添加,代碼如下:
在refresh中的finishRefresh()方法中,會調用publishEvnet(new ContextRefreshedEvent(this))發布事件。進行多播器廣播,代碼如下
最終會調到FrameworkServlet.this.onApplicationEvent(event)。
⑶ 詳解Spring mvc工作原理及源碼分析
Model 模型層 (javaBean組件 = 領域模型(javaBean) + 業務層 + 持久層)
View 視圖層( html、jsp…)
Controller 控制層(委託模型層進行數據處理)
springmvc是一個web層mvc框架,類似struts2。
springmvc是spring的部分,其實就是spring在原有基礎上,又提供了web應用的mvc模塊。
實現機制:
struts2是基於過濾器實現的。
springmvc是基於servlet實現的。
運行速度:
因為過濾器底層是servlet,所以springmvc的運行速度會稍微比structs2快。
struts2是多例的
springmvc單例的
參數封裝:
struts2參數封裝是基於屬性進行封裝。
springmvc是基於方法封裝。顆粒度更細。
⑴ 用戶發送請求至DispatcherServlet。
⑵ DispatcherServlet收到請求調用HandlerMapping查詢具體的Handler。
⑶ HandlerMapping找到具體的處理器(具體配置的是哪個處理器的實現類),生成處理器對象及處理器攔截器(HandlerExcutorChain包含了Handler以及攔截器集合)返回給DispatcherServlet。
⑷ DispatcherServlet接收到HandlerMapping返回的HandlerExcutorChain後,調用HandlerAdapter請求執行具體的Handler(Controller)。
⑸ HandlerAdapter經過適配調用具體的Handler(Controller即後端控制器)。
⑹ Controller執行完成返回ModelAndView(其中包含邏輯視圖和數據)給HandlerAdaptor。
⑺ HandlerAdaptor再將ModelAndView返回給DispatcherServlet。
⑻ DispatcherServlet請求視圖解析器ViewReslover解析ModelAndView。
⑼ ViewReslover解析後返回具體View(物理視圖)到DispatcherServlet。
⑽ DispatcherServlet請求渲染視圖(即將模型數據填充至視圖中) 根據View進行渲染視圖。
⑾ 將渲染後的視圖返回給DispatcherServlet。
⑿ DispatcherServlet將響應結果返回給用戶。
(1)前端控制器DispatcherServlet(配置即可)
功能:中央處理器,接收請求,自己不做任何處理,而是將請求發送給其他組件進行處理。DispatcherServlet 是整個流程的控制中心。
(2)處理器映射器HandlerMapping(配置即可)
功能:根據DispatcherServlet發送的url請求路徑查找Handler
常見的處理器映射器:BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping,
,(不建議使用)
(3)處理器適配器HandlerAdapter(配置即可)
功能:按照特定規則(HandlerAdapter要求的規則)去執行Handler。
通過HandlerAdapter對處理器進行執行,這是適配器模式的應用,通過擴展多個適配器對更多類型的處理器進行執行。
常見的處理器適配器:HttpRequestHandlerAdapter,,
(4)處理器Handler即Controller(程序猿編寫)
功能:編寫Handler時按照HandlerAdapter的要求去做,這樣適配器才可以去正確執行Handler。
(5)視圖解析器ViewReslover(配置即可)
功能:進行視圖解析,根據邏輯視圖名解析成真正的視圖。
ViewResolver負責將處理結果生成View視圖,ViewResolver首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成View視圖對象,最後對View進行渲染將處理結果通過頁面展示給用戶。
springmvc框架提供了多種View視圖類型,如:jstlView、freemarkerView、pdfView...
(6)視圖View(程序猿編寫)
View是一個介面,實現類支持不同的View類型(jsp、freemarker、pdf...)
引入相關依賴:spring的基本包、springmvc需要的spring-webmvc,日誌相關的slf4j-log4j12,jsp相關的jstl、servlet-api、jsp-api。
因為DispatcherServlet本身就是一個Servlet,所以需要在web.xml配置。
一、使用默認載入springmvc配置文件的方式,必須按照以下規范:
①命名規則:-servlet.xml ====> springmvc-servlet.xml
②路徑規則:-servlet.xml必須放在WEB-INF下邊
二、如果要不按照默認載入位置,則需要在web.xml中通過標簽來指定springmvc配置文件的載入路徑,如上圖所示。
將自定義的 Controller 處理器配置到 spring 容器中交由 spring 容器來管理,因為這里的 springmvc.xml 配置文件中處理器映射器配置的是 BeanNameUrlHandlerMapping ,根據名字可知這個處理器映射器是根據 bean (自定義Controller) 的 name 屬性值url去尋找執行類 Handler(Controller) , 所以bean的name屬性值即是要和用戶發送的請求路徑匹配的 url 。
根據視圖解析路徑:WEB-INF/jsps/index.jsp
功能:根據bean(自定義Controller)的name屬性的url去尋找執行類Controller。
功能:自定義的處理器(Controller)實現了Controller介面時,適配器就會執行Controller的具體方法。
會自動判斷自定義的處理器(Controller)是否實現了Controller介面,如果是,它將會自動調用處理器的handleRequest方法。
Controller介面中有一個方法叫handleRequest,也就是處理器方法。
因此,自定義的Controller要想被調用就必須實現Controller介面,重寫Controller介面中的處理器方法。
⑷ Spring源碼解析(一)- 容器的基本實現
Spring使用 基本的JavaBean 來完成以前只可能由EJB完成的事情,是個分層架構。Spring創建bean都需要通過 讀取 、 解析 、 校驗配置文件, 然後注冊創建成Bean。 Spring是一個Bean容器 , 主要作用是替我們管理bean對象 (簡單的Java類對象的生命周期)。不管框架如何強大,還是需要我們程序員來告訴其一些必要信息的(比如要 管理的bean對象的類相關信息、是否開啟組件掃檔納描 等),這些我們稱之為對 Spring框架的配置 ,目前主流的配置方式是 通過使用配置文件或註解。
Spring中最核心的兩個源雀類: DefaultListableBeanFactory、XmlBeanDifinitionReader。DefaultListableBeanFactory 是整個bean載入的核心部分,是Spring注冊及載入bean的默認實現 。XmlBeanDefinitionReader 主要使用reader屬性對資源文件進行讀取和注冊。
XML配置文件讀取是Spring中重要的功能,大部分Spring大部分功能都是 以配置作為切入點 。 XmlBeanFactory 繼承自 DefaultListableBeanFactory ,而對於 DefaultListableBeanFactory 不同的地方其實是在 XmlBeanFactory 中使用了自定義的XML讀取器 XmlBeanDefinitionReader ,主要用於從XML文檔中讀取 BeanDefinition, 實現了個性化的 BeanDefinitionReader 讀取, DefaultListableBeanFactory 繼承了 並實現了 以及 BeanDefinitionRegistry 介面。
Spring的配置文件讀取是通過ClasaPathResource進行封裝的 ,如:new ClassPathResource("bean.xml")。在java中, 將不同來源的資源的讀取邏輯抽象成URL ,通過注冊不同的 handler來處理。 一般handler的類型使用不同的前綴,URL沒有默認定義相對的path路徑,也 沒有提供相關方法對資源進行檢查 ,顧Spring對其內部需要使用到的資源做了屬於自己的抽象結構, 用Resource介面來封裝底層資源。
Resource 介面繼承 InputStreamSource(封裝了任何能返回InputStream的類)。
Resource介面抽象了所有Spring內部使用到的底層資源 ,首先它定義了3個能判斷當前資源狀態的方法: 存在性(exists)、可讀性(isReadable)、是否處於打開狀態(isOpen) 。有了Resource介面便可以對所有資源進行統一處理。 ClassPathResource 中的實現是通過class或 classLoader 提供的底層方法進行調用。以此完成對配置文件資源的封裝。
當通過Resource相關類完成了對配置文件進行封裝,接下來由 XmlBeanDefinitionReader 完成對配置文件的讀取工作。雹蠢早
XML文件的驗證模式有兩種:DTD、XSD(XML Schema).
DTD即文檔類型定義, 是一種XML約束模式語言,是XML文件的驗證機制 。是一種保證XML文檔格式正確的有效方法, 可以通過比較XML文檔和DTD文件來查看文檔是否符合規范,元素和標簽的使用是否正確 。一個DTD文檔包含:元素的定義規則、元素間關系的定義規則、元素可使用的屬性、可使用的實體或符號規則。 要使用DTD驗證模式需要在XML文件的頭部聲明。
XML Schema語言就是XSD。 XML Schema描述了XML文檔的結構。可以用一個指定的XML Schema來驗證某個XML文檔,以檢查該XML文檔是否符合其要求。也可以 通過XML Schema指定一個XML文檔所允許的結構和內容 。XML Schema本身也是一個XML文檔,符合XML語法結構,可以用通用的XML解析器解析它。
使用XML Schema文檔對XML實例進行校驗,要聲明名稱空間和指定該名稱空間所對應的XML Schema文檔存儲位置 。通過schemaLocation屬性來指定名稱空間所對應的XML Schema文檔的存儲地址(1、名稱空間URL;2、該名稱空間所標識的XML Schema文件地址或URL地址)。
另外驗證模式通過 XmlBeanDefinitionReader 中的setValidationMode方法進行設定。而 Spring 用來檢測驗證模式的方法實際上就是判斷是否包含 DOCTYPE ,如果包含就是 DTD ,否則就是 XSD 。
XML文件經過驗證模式,交由DocumentLoader進行解析成對應的 Document。 而解析的過程中存在這么一環節:(EntityResolver) 根據聲明去尋找對應的DTD定義,以便對文檔進行驗證認證 。也可以通過setEntityResolver設置DTD定義。EntityResolver它用來接收兩個參數publicId和systemId,xsd格式文件通常publicId為null。而對於不同的驗證模式採用不同的解析器進行解析,並把文件轉換成Document文件,用於提取及注冊bean。
Document 文件通過 BeanDefinitionDocumentReader 進行內部邏輯處理,並提取root用於作為參數繼續完成BeanDefinition的注冊。
⑸ 怎麼閱讀Spring源碼
學習源碼是一件非常耗時費力的事情,需要有足夠的時間和持久的耐心,下面是我閱讀郝佳老師的《Spring源碼深度解析》所做的記錄,書中以Spring3.2講解,使用jdk1.7。
准備工作
1. 安裝github:現在spring源代碼都在github管理,所以首先需要下載githup,下;
2. 安裝gradle構建工具: 下載完後進行解壓到任意盤符,然後增加環境變數GRADLE_HOME,並在環境變數bin中增加%GRADLE_HOME%/bin,打開DOS窗口,運行gradle -v,出現版本號等信息,表示安裝成功;
3. 下載Spring源碼:首先打開git shell,切換到你的工作目錄,然後輸入以下命令:git clone git://github.com/SpringSource/Spring-framework.git,後面一串是源碼下載地址。大概半小時的樣子,就可以下載完成,這時候在你的工作目錄中就會出現Spring-framework的目錄,裡面有Spring各組件的源碼包;
4. 構建導入:下載下來的代碼不能直接導入Eclipse,要先轉換成Eclipse能讀取的形式。因為所有組件都會依賴spring-core,所有我們首先要轉換Spring-core工程,在命令窗口切換到Spring-core工程,運行gradle cleanidea eclipse命令,我們會看到開始下載工程所依賴的jar包,幾分鍾後執行完畢,再來看Spring-core文件夾,多了.classpath、.project等文件,這是Eclipse工程所必須的,然後可以把他導入到eclipse。因為大部分Spring組件都會用到 spring-beans、spring-context、spring-aop,而他們又依賴spring-expression、spring-instrument,所以我們乾脆先把這些工程都進行轉換並導入eclipse。