執行鏈的執行是按照配置文件的前後順序執行的。當執行到handle的時候,會去請求合適的HandleAdapter去執行,而不是本身執行。執行以後返回一個ModelAndView對象。以後在請求一個ViewResolver來解析ModelAndView對象獲得View對象,這個對象能夠用於解析和渲染獲得最終的數據。html
ore Container(核心容器)包含Core、Beans、Context和Expression Language模塊。Core和Beans模塊是框架的基礎部分,提供IoC(控制反轉)和依賴注入特性。此處涉及到的基礎概念是BeanFactory,其提供對於Factory模式的經典實現來消除對程序性單例模式的須要,並真正的容許從程序邏輯中分離出依賴關係和配置。程序員
Data Access/Integration包含JDBC、ORM、OXM、JMX和Transaction模塊。web
JDBC模塊提供一個JDBC抽象層,能夠徹底消除冗長的JDBC編碼和解析數據庫廠商特有的錯誤代碼。此模塊包含了Spring對JDBC數據訪問進行封裝的全部類。面試
ORM模塊爲流行的對象-關係映射API,如JPA、JDO、Hibernate、iBatis等,提供了一個交互層。利用ORM封裝包,能夠混合使用全部Spring提供的特性進行O/R映射。spring
OXM模塊提供了一個對Object/XML映射實現的抽象層,Object/XML映射實現包括JAXB、Castor、XMLBeans、JiBX和XStream。數據庫
JMS(Java Messaging Service)包含了一些製造和消息消息的特性。編程
Transaction模塊支持編程和聲明性的事物管理,這些事物必須實現特定的接口,而且對全部的POJO適用。數組
Web上下文模塊創建在應用程序上下文模塊之上,爲基於Web的應用程序提供上下文。同時,該模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工做。緩存
Web模塊提供了基礎的面向Web的集成特性。例如,多文件上傳、使用servlet listeners初始化IoC容器以及一個面向Web的應用上下文,還包含了Spring遠程支持中Web的相關部分。服務器
Web-Servlet模塊(web.servlet.jar)包含了Spring的model-view-controller(MVC)實現。Spring的MVC框架使得模型範圍內的代碼和web forms之間可以清楚地分離開來,並與Spring框架的其餘特性集成在一塊兒。
Web-Struts模塊提供了對Struts的支持,使得類在Spring應用中可以與一個典型的Struts Web層集成在一塊兒。(PS:此支持在Spring3.0中是deprecated的)。
Web-Portlet模塊提供了用於Portlet環境和Web-Servlet模塊的MVC的實現。
AOP模塊提供了一個符合AOP聯盟標準的面向切面編程的實現,能夠定義例如方法攔截器和切點,從而將邏輯代碼分開,下降耦合性。利用source-level的元數據功能,還能夠將各類行爲信息合併到代碼中。經過配置管理特性,該模塊直接將面向切面的編程集成到框架中,進而是框架管理的對象支持AOP。同時,該模塊爲基於Spring的應用程序中的對象提供了事務管理服務。經過使用Spring AOP,不用依賴EJB組件,就能夠將聲明性事務管理集成到應用程序中。
Aspects提供了對AspectJ的集成支持。
Instrumentation提供了class instrumentation支持和classloader實現,進而能夠在特定的應用服務器上使用。
beanfactory and applicationcontext的區別
IoC: 控制反轉,是一種思想,表示將由程序員自動建立對象的權限交由spring框架來管理。當使用spring 的時候,對象的建立和其生命週期的維護全權交由spring來作,咱們只要給出依賴的配置便可。
Spring IoC容器的設計主要基於下面的兩個主要的接口
其中,ApplicationContext是BeanFactory的派生接口,可是它實現了更多,更全面的功能,也就是一種更加高級的接口,最經常使用的一個實現類就是ClassPathXMLApplicationContex類。所以,在絕大部分的時候使用ApplicationContext。
BeanFactory: 是Spring中最底層的接口,只提供了最簡單的IoC功能,負責配置,建立和管理bean。在應用中,通常不使用 BeanFactory,而推薦使用ApplicationContext
ApplicationContext:
雖然 Spring IoC 容器的生成十分的複雜,可是大致瞭解一下 Spring IoC 初始化的過程仍是必要的。這對於理解 Spring 的一系列行爲是頗有幫助的。
使用任何一個類,都須要先定義,聲明,初始化這三個步驟。
Resource 定位 Spring IoC 容器先根據開發者的配置,進行資源的定位,在 Spring 的開發中,經過 XML 或者註解都是十分常見的方式,定位的內容是由開發者提供的。
BeanDefinition 的載入 這個時候只是將 Resource 定位到的信息,保存到 Bean 定義(BeanDefinition)中,此時並不會建立 Bean 的實例
BeanDefinition 的註冊 這個過程就是將 BeanDefinition 的信息發佈到 Spring IoC 容器中 注意:此時仍然沒有對應的 Bean 的實例。
最後咱們簡單說說IoC是如何實現的。想象一下若是咱們本身來實現這個依賴注入的功能,咱們怎麼來作? 無外乎:
讀取標註或者配置文件,看看JuiceMaker依賴的是哪一個Source,拿到類名 使用反射的API,基於類名實例化對應的對象實例 將對象實例,經過構造函數或者 setter,傳遞給 JuiceMaker
若是使用ApplicationContext,若是配置的bean是singleton,那麼無論你有沒有或想不想用它,它都會被實例化。好處是能夠預先加載,壞處是浪費內存。
BeanFactory,當使用BeanFactory實例化對象時,配置的bean不會立刻被實例化,而是等到你使用該bean的時候(getBean)纔會被實例化。好處是節約內存,壞處是速度比較慢。多用於移動設備的開發。
沒有特殊要求的狀況下,應該使用ApplicationContext完成。由於BeanFactory能完成的事情,ApplicationContext都能完成,而且提供了更多接近如今開發的功能。
Spring上下文中的Bean也相似,【Spring上下文的生命週期】
其實在初始化以前的不少東西很像是一個聲明,註冊的一個過程,使得spring 能夠對此bean進行必要的控制的過程。
1:先經過掃描指定包路徑下的spring註解,好比@Component、@Service、@Lazy @Sope等spring識別的註解或者是xml配置的屬性(經過讀取流,解析成Document,Document)而後spring會解析這些屬性,將這些屬性封裝到BeanDefintaion這個接口的實現類中.
好比這個配置Bean,spring也會將className、scope、lazy等這些屬性裝配到PersonAction對應的BeanDefintaion中.具體採用的是BeanDefinitionParser接口中的parse(Element element, ParserContext parserContext)方法,該接口有不少不一樣的實現類。經過實現類去解析註解或者xml而後放到BeanDefination中,BeanDefintaion的做用是集成了咱們的配置對象中的各類屬性,重要的有這個bean的ClassName,還有是不是Singleton、對象的屬性和值等(若是是單例的話,後面會將這個單例對象放入到spring的單例池中)。spring後期若是須要這些屬性就會直接從它中獲取。而後,再註冊到一個ConcurrentHashMap中,在spring中具體的方法就是registerBeanDefinition(),這個Map存的key是對象的名字,好比Person這個對象,它的名字就是person,值是BeanDefination,它位於DefaultListableBeanFactory類下面的beanDefinitionMap類屬性中,同時將全部的bean的名字放入到beanDefinitionNames這個list中,目的就是方便取beanName;
spring的bean生命週期其實最核心的分爲4個步驟,只要理清三個關鍵的步驟,其餘的只是在這三個細節中添加不一樣的細節實現,也就是spring的bean生明週期:
實例化和初始化的區別:實例化是在jvm的堆中建立了這個對象實例,此時它只是一個空的對象,全部的屬性爲null。而初始化的過程就是講對象依賴的一些屬性進行賦值以後,調用某些方法來開啓一些默認加載。好比spring中配置的數據庫屬性Bean,在初始化的時候就會將這些屬性填充,好比driver、jdbcurl等,而後初始化鏈接
AbstractAutowireCapableBeanFactory.doCreateBean中會調用createBeanInstance()方法,該階段主要是從beanDefinitionMap循環讀取bean,獲取它的屬性,而後利用反射(core包下有ReflectionUtil會先強行將構造方法setAccessible(true))讀取對象的構造方法(spring會自動判斷是不是有參數仍是無參數,以及構造方法中的參數是否可用),而後再去建立實例(newInstance)
複製代碼
初始化主要包括兩個步驟,一個是屬性填充,另外一個就是具體的初始化過程
PopulateBean()會對bean的依賴屬性進行填充,@AutoWired註解注入的屬性就發生這個階段,假如咱們的bean有不少依賴的對象,那麼spring會依次調用這些依賴的對象進行實例化,注意這裏可能會有循環依賴的問題。後面咱們會講到spring是如何解決循環依賴的問題
複製代碼
初始化的過程包括將初始化好的bean放入到spring的緩存中、填充咱們預設的屬性進一步作後置處理等
複製代碼
在Spring將全部的bean都初始化好以後,咱們的業務系統就能夠調用了。而銷燬主要的操做是銷燬bean,主要是伴隨着spring容器的關閉,此時會將spring的bean移除容器之中。此後spring的生命週期到這一步完全結束,再也不接受spring的管理和約束。
複製代碼
spring單例對象的初始化大略分爲三步:
從上面講述的單例bean初始化步驟咱們能夠知道,循環依賴主要發生在第1、第二步。也就是構造器循環依賴和field循環依賴。 接下來,咱們具體看看spring是如何處理三種循環依賴的。
這三級緩存的做用分別是: singletonFactories : 進入實例化階段的單例對象工廠的cache (三級緩存) earlySingletonObjects :完成實例化可是還沒有初始化的,提早暴光的單例對象的Cache (二級緩存) singletonObjects:完成初始化的單例對象的cache(一級緩存)
經過查詢第三級緩存能夠知道哪些對象其實已經建立,能夠依賴了,儘管此時尚未完成初始化的整個流程。這樣就能夠提早終止了依賴圈。
這樣作有什麼好處呢?讓咱們來分析一下「A的某個field或者setter依賴了B的實例對象,同時B的某個field或者setter依賴了A的實例對象」這種循環依賴的狀況。A首先完成了初始化的第一步,而且將本身提早曝光到singletonFactories中,此時進行初始化的第二步,發現本身依賴對象B,此時就嘗試去get(B),發現B尚未被create,因此走create流程,B在初始化第一步的時候發現本身依賴了對象A,因而嘗試get(A),嘗試一級緩存singletonObjects(確定沒有,由於A還沒初始化徹底),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,因爲A經過ObjectFactory將本身提早曝光了,因此B可以經過ObjectFactory.getObject拿到A對象(雖然A尚未初始化徹底,可是總比沒有好呀),B拿到A對象後順利完成了初始化階段一、二、3,徹底初始化以後將本身放入到一級緩存singletonObjects中。此時返回A中,A此時能拿到B的對象順利完成本身的初始化階段二、3,最終A也完成了初始化,進去了一級緩存singletonObjects中,並且更加幸運的是,因爲B拿到了A的對象引用,因此B如今hold住的A對象完成了初始化。
全部的類都是在第一次使用時,被動態加載到jvm內存中,即首次建立對象時,或者類中的靜態方法首次被調用時,或者靜態屬性被訪問時,類加載器定位找到對應的class文件;
類加載器把class文件載入內存,並生成class對象,把對象中全部的靜態資源都執行一遍,並把這些靜態資源存放到jvm的方法區中,有且只在class對象首次生成時執行一次;
new建立對象時,首先檢查該類的class文件是否已加載到jvm內存中並生成class對象,如有,則會在jvm堆內存中爲該類分配足夠的空間;
把存儲的空間清空,並把該類的全部的基本數據類型設置成默認值,對象引用設置null;
繼續執行字段中被自定義的值的一些初始化操做;
調用構造方法,便建立了一個對象。
new的對象在編譯環境中要必須在類路徑中有,class.forName()在編譯時能夠不在類路徑中,因此class.forName()指定了ClassLoader後,就能夠在指定的環境中查找某些類,即:new一個對象容許class文件還沒加載進來,jvm虛擬機會自動檢查內存中是否有這個class對象,若沒有就經過類加載器加載進來,而newInstance()必需要確保class文件已經加載進內存中才能產生一個對象,這時需經過class.foName()方法加載class文件。
newInstance()其實是把new這個方式分解爲兩步,即首先調用Class加載方法加載某個類,而後實例化。