正本文參考了《spring技術內幕》和spring 4.0.5源碼。本文只描述原理流程的主線部分,其餘好比驗證,緩存什麼能夠具體參考源碼理解。正則表達式
容器的初始化首先是在對應的構造器中進行,在applicationContext的實現類構造器中,首先對參數路徑中的${}進行了處理,用系統變量替換(setConfigLocations方法)而後調用refresh方法(這個就是最核心的容器初始化方法)。
spring
在refresh方法中調用obtainFreshBeanFactory方法告訴子類刷新beanfactory(其中是調用refreshBeanFactory刷新後getBeanFactory獲取刷新後的factory返回)。在刷新過程refreshBeanFactory中若是factory已經有了要消除再新建factory,其中loadBeanDefinitions是加載bean定義的方法。
在loadBeanDefinitions方法中建立了BeanDefinitionReader的實現類調用其loadBeanDefinitions方法(這個方法是重載方法,參數有爲Resource的也有爲String路徑的,getConfigResources方法(默認返回null,子類重寫,如ClassPathXmlApplicationContext類)和getConfigLocations方法得到Resource集合和資源路徑集合(通常一個爲空,通常是將容器的參數path設定爲configLocations,ClassPathXmlApplicationContext有一種構造器是不設定configLocations而是直接用參數path生成ClassPathResource集合設定爲configResources)分別進行load,實際上以路徑爲參數的重載方法在定位完Resource也會調用以resource爲參數的loadBeanDefinitions來解析載入BeanDefinition,這個是第二步在下面介紹)。
在BeanDefinitionReader的loadBeanDefinitions(path參數)方法中根據ResourceLoader類型以兩種方式加載(若是是ant正則表達式方式的(如PathMatchingResourcePatternResolver)一個路徑定位多個resource或者默認方式(applicationContext繼承的是DefaultResourceLoader實現方式)定位一個resource),分別調用ResourceLoader的getResource(以/開頭的構建ClassPathContextResource,以classpath開頭的去掉classpath構建ClassPathResource,若是都不是的嘗試構建UrlResource,若是構建失敗就調用getResourceByPath這個具體applicationContext實現類裏重寫的方法構建特定Resource,如FileSystemXmlApplicationContext就是FileSystemResource)或getResources(PathMatchingResourcePatternResolver的正則方式這裏不詳細描述)完成Resource定位。緩存
一樣在BeanDefinitionReader的loadBeanDefinitions中調用完resourceLoader的getResource獲取Resource後將resource做爲參數調用本身(BeanDefinitionReader)的loadBeanDefinitions(是一個接口方法給子類實現,由於不一樣的reader加載resource的方式不一樣)載入BeanDefinition。
例如XmlBeanDefinitionReader是對XML文件的IO操做,(將如今要處理的Resource加入當前線程正在處理(ThreadLocal)的Resource集合中)首先從resource中拿出InputStream封裝成InputSource調用自身的doLoadBeanDefinitions方法。
doLoadBeanDefinitions方法中調用doLoadDocument方法封裝成Document-----是用validationMode(默認是自動校驗方式,意思是若是沒有顯示定義校驗的方式就用XSD方式)和DocumentLoader(XmlBeanDefinitionReader中默認的是DefaultDocumentLoader)等參數調用DocumentLoader的loadDocument方法將Resource封裝成Document類(具體封裝方式不作介紹,有興趣的能夠本身瞭解一下,用的是builder模式作的)調用registerBeanDefinitions方法解析載入bean。
registerBeanDefinitions方法是用BeanDefinitionDocumentReader的registerBeanDefinitions具體解析Document(樹形結構,從root(就是beans標籤)開始往下解析)中每一個element各個標籤的解析和載入。其中若是是bean標籤BeabDefinitionParserDelegate的parseBeanDefinitionElement方法對XML元素的信息按照spring的bean的規則進行解析(property的解析,當中value和ref解析方式不一樣,若是是value構建TypedStringValue, 若是ref的話構建RuntimeBeanReference,這個在以後依賴注入的時候用到,還有id,name,等屬性的解析)獲得的BeanDefinition的封裝BeanDefinitionHolder(包括BeanDefinition,beanName(這裏是標識符的意思,若是有id,id作標識符,沒有id,name屬性中第一個別名作標識符)和別名列表(name屬性中的內容,若是沒有id,name中第一個不做爲別名而是標識符))來進行下一步bean的註冊(BeanDefinitionReaderUtils.registerBeanDefinition)。
其餘如import,alias等標籤自行看源碼理解。session
BeanDefinitionReaderUtils.registerBeanDefinition用BeanDefinitionRegistry(DefaultListableBeanFactory)的registerBeanDefinition方法註冊beanName和BeanDefinition(就是把beanName加入到一個已經註冊的bean的beanName的Set中,而後put到beanName對應BeanDefinition的map中,其中若是不容許覆蓋而且有同名beanName要報錯)。再用BeanDefinitionRegistry的registerAlias方法註冊beanName和別名列表(put到一個beanName對應alias的map中,其中若是有alias跟beanName相同的要移除)。app
是以BeanFactory的getBean方法爲入口觸發的(實如今AbstractBeanFactory實現類中)。若是是單例會緩存起來只加載一次,若是是FactoryBean這種特殊的bean會把這個bean的實例傳入getObjectForBeanInstance方法得到FactoryBean產生的bean(調用FactoryBean的getObject方法,這就是自定義的FactoryBean要重寫的方法,AOP也是這個原理,詳情見下方AOP分析)。在第一次載入時要先判斷這個BeanDefinition在當前BeanFactory有沒有,沒有就從雙親BeanFactory中找,一直遞歸。
找到後要驗證是否存在遞歸依賴,有則報錯無則設置當前bean依賴bean的依賴關係到兩個map中(一個是被依賴map,一個是依賴map),其中:
(1)若是是單例第一次載入就調用getSingleton方法(方法中回調了參數中ObjectFactory的getObject方法,這裏重寫了這個方法調用createBean)得到實例用getObjectForBeanInstance得到FactoryBean產生的bean(若是它是FactoryBean的話)。
(2)若是是prototype加載調用createBean後調用getObjectForBeanInstance。
(3)若是是其餘scope類型:request、session和global session,這三種就用scope.get獲取實例(和getSingleton相似回調重寫的getObject也就是調用createBean)後調用getObjectForBeanInstance。
最後若是getBean指定了requiredType要檢驗獲取的bean能不能轉化成指定的類型不能的話就報錯。
createBean方法就是生成bean的方法並對一些好比init-method屬性、後置處理器等一些初始化進行了處理。方法中在實例化以前判斷是否有post-processor,若是有這樣的processor則短路指定bean的建立,直接返回一個proxy而不是指定的bean(這種processor能夠指定生成一個其餘類型的對象)沒有的話用doCreateBean建立bean返回。
doCreateBean是用createBeanInstance生成BeanWrapper(包裝bean)以後用populateBean向其中的bean完成依賴bean的注入(autowire等)。
createBeanInstance建立beanWrapper時分三類進行處理:
(1)若是有工廠方法,調用instantiateUsingFactoryMethod建立。
(2)若是是構造器注入的方式調用autowireConstructor。
(3)簡單方式調用instantiateBean。調用的是策略類(默認SimpleInstantiationStrategy)的instantiate而其中又是經過bean方法是否有跟IOC容器同名的(會被覆蓋)來分兩類處理(沒同名方法的從BeanDefinition中拿出class直接用jdk的反射拿構造器來newinstance一個實例,若是有同名的則是用CGLIB的方式來new一個實例)。
populateBean爲生成的bean依賴注入,先對非簡單類型屬性有autowire的進行處理,判斷這個屬性在以前解析載入beanDefinition時property裏有沒有,有的話進行getBean初始化後放入PropertyValue集合中(這個就是propertyname和value的封裝),而後更新依賴map,再對非autowire的或通常屬性進行注入,有要轉化的要通過valueResolver的轉化(若是是RuntimeBeanReference以前載入時XML中配置是ref的就getBean(若是在雙親BeanFactory中就從雙親中取)得到後也放到PropertyValue集合中,也要更新依賴map)。最後再注入到bean中,這裏說的注入其實真實發生在最後的BeanWraper的setPropertyValue(propertyValue集合)方法,具體實現就是經過反射的方式得到setter方法賦值。post
在refresh方法中的finishBeanFactoryInitialization方法中進行初始化(實際也是調用getBean方法)。ui
ProxyFacotryBean是FacotryBean的一種實現,FacotryBean要產生bean都要重寫getObject方法,而ProxyFacotryBean這裏的這個getObject正是爲代理作了準備並返回代理對象。首先用initializeAdvisorChain(第一次去取代理對象時初始化一遍)初始化Advisor鏈後對於singleton和prototype進行區分生成對應的proxy。
spa
initializeAdvisorChain初始化Advisor鏈是遍歷ProxyFacotryBean中配置的interceptorNames,若是結尾有通配符只能是ListableBeanFacotory來加載不然報錯,去掉結尾通配符*後調用addGlobalAdvosor(這個是獲取ListableBeanFacotory的全部globalAdvisorNames和globalInterceptorNames,分別遍歷用getBean(beanName)獲取advice,把其中符合通配符格式的advice調用addAdvisorOnChainCreation封裝成advicsor後添加到Advisor鏈,若是結尾沒有通配符的狀況下不管是singleton仍是prototype在得到advice後都要用addAdvisorOnChainCreation方法註冊到advisor鏈上。
addAdvisorOnChainCreation用namedBeanToAdvisor方法把advice包裝成advisor,判斷若是advice是單例singleton的話是用AdvisorAdapterRegistry(默認DefaultAdvisorAdapterRegistry單例)wrap方法判斷若是這個advice是MethodInterceptor或者AdvisorAdapterRegistry三種固定的adapter(before,afterreturning,throws)若是任一adapter支持的話(支持不支持就是在具體的adapter中判斷advice是否是這個adapter對應具體的advice類的子類)就封裝成DefaultPointcutAdvisor返回。若是是prototype的話不獲取getBean,而是直接用name包裝成PrototypePlaceholderAdvisor。prototype
以singleton爲例,singleton代理的生成getSingletonInstance方法。是用AopProxyFactory(在構造器中設定了默認的DefaultAopProxyFactory)的createAopProxy方法根據ProxyFacotryBean中配置的target判斷是不是個接口(實際上不是這麼簡單的區分,具體看源碼瞭解)來建立不一樣AopProxy的子類(JdkDynamicAopProxy或者ObjenesisCglibAopProxy(CglibAopProxy的子類,增長了ObjenesisStd))調用他們各自的getProxy方法以不一樣的方式建立代理對象返回。
JdkDynamicAopProxy就是以動態代理的方式構建代理對象返回(具體動態代理原理自行了解哦)。
CglibAopProxy就是以Cglib的方式進行代理,Cglib採用了很是底層的字節碼技術,其原理是經過字節碼技術爲一個類建立子類,並在子類中採用方法攔截的技術攔截全部父類方法的調用,順勢織入橫切邏輯。具體細節超出這文章的範圍拉。
prototype代理的方式大體相同有些許的差異也不作介紹,能夠參考源碼。線程
在調用目標類的方法時由於代理調用的是invoke(jdk動態代理)或者intercept(cglib)。在invoke(jdk動態代理)或者intercept(cglib)中根據目標類被調用方法分別處理。 若是是hashCode和equals方法直接調用代理類中重寫了的hashCode和equals方法(具體參考源碼)。 若是是Adviced接口中定義的方法(ProxyFactoryBean就是Adviced接口實現類)直接以反射的方式拿到method調用方法(AopUtils的invokeJoinpointUsingReflection方法)。 其餘狀況就是拿到攔截器鏈(只初始化一次,每次調用時有個currentInterceptorIndex記錄處理到第幾個攔截器)調用攔截器的proceed方法前進調用。 proceed前進調用不是遞歸,其中用matcher進行匹配,若是匹配上調用攔截器的invoke方法,匹配不上就直接繼續前進調用,攔截器interceptor的invoke方法就是通知方法(本身實現的如afterReturning等)對目標方法(實際是攔截器鏈的proceed前進調用)的具體增強,就是順序問題等等。 直到攔截器鏈前進到底調用target目標類的對應方法(jdk反射獲取method調用)。 初始化攔截器鏈是經過遍歷以前IOC容器getBean獲取到advisor鏈中的Advisor,經過AdvisorAdapterRegistry當中設置的3種adapter(before,afterreturning,throws)的supportsAdvice判斷是否支持該advisor,若是支持就將advisor中的advice註冊成不一樣的AdviceInterceptor列表(一個advisor能夠被多個adapter支持,由於只要本身寫的通知類實現多種advice接口便可)都加入到攔截器鏈。