Spring源碼啟動(dòng)過程以及拓展點(diǎn)

容器啟動(dòng)過程

  1. 第一步先調(diào)用this()浓恳;構(gòu)造方法缺狠,這時(shí)父類構(gòu)造器會(huì)初始化容器的 beanFactory 屬性宇攻,屬性為DefaultListableBeanFactory尖淘,帶有存儲(chǔ)BeanDefinition 和單例 bean 的功能
  • 新建一個(gè)注解Bean定義讀取器 new AnnotatedBeanDefinitionReader(this); 這個(gè)讀取器主要是初始化環(huán)境變量,以及注冊(cè) 一些創(chuàng)世紀(jì)的 BeanDefinition 【例如:ConfigurationClassPostProcessor著觉、AutowiredAnnotationBeanPostProcessor德澈、CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor固惯、DefaultEventListenerFactory】
  • 新建一個(gè)類路徑掃描器ClassPathBeanDefinitionScanner
  1. 容器調(diào)用register(componentClasses);把啟動(dòng)類注冊(cè)成BeanDefinition放入到容器中
  2. 啟動(dòng)Spring,調(diào)用 refresh() 方法去刷新容器
  3. prepareRefresh() 準(zhǔn)備刷新方法缴守,沒有做什么重要的事情葬毫,主要是設(shè)置了下容器的啟動(dòng)狀態(tài)
  4. 調(diào)用obtainFreshBeanFactory();獲取到容器的工廠,DefaultListableBeanFactory
  5. 調(diào)用prepareBeanFactory(beanFactory)
  • 設(shè)置容器的類加載器
  • 設(shè)置Spring容器中需要忽略的set方法
  • ResourceEditorRegistrar注冊(cè)資源編輯器屡穗,當(dāng)Bean初始化的時(shí)候贴捡,構(gòu)造器上需要注入Spring資源相關(guān)的Bean時(shí),由該類注入
  • 注冊(cè)三個(gè)BeanPostProcessor到容器中【ApplicationContextAwareProcessor (會(huì)在Bean初始化前村砂,調(diào)用烂斋,例如ApplicationContextAware接口,會(huì)注入ApplicationContext容器到類中)础废、LoadTimeWeaverAwareProcessor (織入Bean后置處理器)】
  1. 調(diào)用postProcessBeanFactory(beanFactory);留給子類來設(shè)置BeanFactory
  2. 調(diào)用invokeBeanFactoryPostProcessors(beanFactory) 方法
  • 第一次調(diào)用已經(jīng)初始化過的 BeanDefinitionRegistryPostProcessor 類的 registryProcessor.postProcessBeanDefinitionRegistry(registry) 方法汛骂,基本上不會(huì)有,除非自己在前面步驟設(shè)置過
  • 第二次調(diào)用實(shí)現(xiàn)了PriorityOrdered的 BeanDefinitionRegistryPostProcessor 接口的類的.postProcessBeanDefinitionRegistry(registry) 方法评腺,一般只會(huì)有 ConfigurationClassPostProcessor 類帘瞭,這個(gè)類在 1.a 步驟中被注冊(cè)成BeanDefinition
    • ConfigurationClassPostProcessor 去解析配置類,如果類是由 @Configuration 注解的類蒿讥,則為 full 配置類蝶念,其他則為 lite 配置類【full配置類,會(huì)生成CGLib動(dòng)態(tài)代理芋绸,@Bean方法只會(huì)調(diào)用一次媒殉,下次就直接獲取上次的對(duì)象;Lite配置類摔敛,則生成普通類】
    • 生成Configuration解析器廷蓉,會(huì)去解析 @ComponentScan 注解包下所有的類,并且會(huì)循環(huán)調(diào)用马昙,知道把所有需要解析成 BeanDefinition 的類都注冊(cè)進(jìn)來 (包括@Component苦酱、@Import、@ImportResource這些注解)
    • 會(huì)解析配置類中有多個(gè)@Bean
  • 調(diào)用實(shí)現(xiàn)了 Ordered 的 BeanDefinitionRegistryPostProcessor 接口的類 的 postProcessBeanDefinitionRegistry(registry) 方法
  • 調(diào)用沒有實(shí)現(xiàn) PriorityOrdered给猾、Ordered 的 BeanDefinitionRegistryPostProcessor 接口的類 的 postProcessBeanDefinitionRegistry(registry) 方法
  • 然后調(diào)用之前所有 BeanDefinitionRegistryPostProcessor 類的 postProcessBeanFactory(beanFactory) 方法疫萤,會(huì)調(diào)用 ConfigurationClassPostProcessor 類
    • ConfigurationClassPostProcessor. postProcessBeanFactory(beanFactory) 會(huì)把Full配置類的BeanDefinition 的類型設(shè)置成CGLIB的動(dòng)態(tài)代理類型,初始化時(shí)敢伸,就是CGLIB動(dòng)態(tài)代理
  • 調(diào)用實(shí)現(xiàn)了PriorityOrdered 的 BeanFactoryPostProcessor 類的 postProcessBeanFactory(beanFactory) 方法
  • 調(diào)用實(shí)現(xiàn)了Ordered 的 BeanFactoryPostProcessor 類的 postProcessBeanFactory(beanFactory) 方法
  • 調(diào)用沒有實(shí)現(xiàn) PriorityOrdered扯饶、Ordered 的 BeanFactoryPostProcessor 類的 postProcessBeanFactory(beanFactory) 方法
    • EventListenerMethodProcessor (會(huì)在所有Bean都實(shí)例化完成后,解析Bean中是否帶有@EventListener方法,如果有尾序,則會(huì)利用EventListenerFactory钓丰,生成一個(gè)ApplicationListener放入容器中)默認(rèn)實(shí)例化出所有 EventListenerFactory 的類
  1. 調(diào)用registerBeanPostProcessors(beanFactory);注冊(cè)Bean的后置處理器到容器中
  • 主要是兩個(gè)后置處理器 internalAutowiredAnnotationProcessor、internalCommonAnnotationProcessor
  • 會(huì)按照優(yōu)先PriorityOrdered然后Ordered每币,最后都沒實(shí)現(xiàn)的BeanPostProcess類的順序放入到容器中
  • 最后放入ApplicationListenerDetector
  1. 調(diào)用 initMessageSource(); 初始化國際化 携丁,一般是DelegatingMessageSource對(duì)象
  2. 調(diào)用 initApplicationEventMulticaster(); 設(shè)置容器的事件多播器為 SimpleApplicationEventMulticaster
  3. 調(diào)用 onRefresh(); 方法,Springboot 就是調(diào)用這個(gè)方法來啟動(dòng)tomcat容器的
  4. 調(diào)用registerListeners();注冊(cè)事件監(jiān)聽器到容器中兰怠,并且如果有早期事件類型梦鉴,則在容器事件廣播器未生成好之前發(fā)布事件
  5. 調(diào)用 finishBeanFactoryInitialization(beanFactory); 實(shí)例化非懶加載的 Bean
  • 先判斷是否有conversionService類型的Bean,如果有揭保,則需要轉(zhuǎn)化生成
  • 實(shí)例化LoadTimeWeaverAware對(duì)象
  • 實(shí)例化Bean
    • 實(shí)例化之前會(huì)先調(diào)用 InstantiationAwareBeanPostProcessor 接口的 postProcessBeforeInstantiation 方法肥橙,這個(gè)時(shí)候可以自己初始化出來,返回給容器
    • 實(shí)例化對(duì)象秸侣,這個(gè)時(shí)候有個(gè)策略 getInstantiationStrategy().instantiate(mbd, beanName, this); 如果是之前設(shè)置了CGLIB動(dòng)態(tài)代理存筏,這里生成的是代理后的對(duì)象
    • 遍歷調(diào)用MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()方法
      • 這里會(huì)調(diào)用 AutowiredAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition 找到所有的 @Autowired或者@Value 注解的方法或?qū)傩裕瑸楹罄m(xù)IOC味榛,依賴注入做準(zhǔn)備
    • 自動(dòng)注入屬性
    • 生成后先遍歷所有的 BeanPostProcessor.postProcessBeforeInitialization(Object bean, String beanName) 方法椭坚,這個(gè)方法可以重新返回一個(gè)新的Bean
      • 所有的 Aware 拓展點(diǎn)在這里實(shí)現(xiàn),通過 ApplicationContextAwareProcessor 類搏色,實(shí)現(xiàn)了EnvironmentAware藕溅、EmbeddedValueResolverAware、ResourceLoaderAware继榆、ApplicationEventPublisherAware巾表、MessageSourceAware、ApplicationContextAware略吨、ApplicationStartupAware等類在這一步注入
    • 實(shí)例化Bean集币,如果Bean實(shí)現(xiàn)了 InitializingBean 接口的Bean,會(huì)調(diào)用它的 afterPropertiesSet 方法
    • 遍歷所有的 BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName) 方法翠忠,這個(gè)方法可以重新返回一個(gè)新的Bean
  • 所有Bean實(shí)例化完成后 便利所有bean鞠苟,調(diào)用實(shí)現(xiàn)了 SmartInitializingSingleton 接口類的afterSingletonsInstantiated方法
  1. 最后調(diào)用 finishRefresh(),發(fā)布容器 publishEvent(new ContextRefreshedEvent(this)); 刷新完成事件

Spring所有拓展點(diǎn)以及順序

  1. 實(shí)現(xiàn)了 BeanDefinitionRegistryPostProcessor 接口的類秽之,調(diào)用 postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 方法当娱,可以獲取到Bean定義的注冊(cè)器,去注冊(cè)BeanDefinition考榨,調(diào)用會(huì)按照先調(diào)用實(shí)現(xiàn)了 PriorityOrdered 接口 再調(diào)用 Ordered 接口 最后再調(diào)用沒有實(shí)現(xiàn) PriorityOrdered 接口 跨细、 Ordered 接口 的 BeanDefinitionRegistryPostProcessor 類
  2. 實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的類,調(diào)用 postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 方法河质,可以獲取到Bean定義的注冊(cè)器冀惭,去注冊(cè)BeanDefinition震叙,調(diào)用會(huì)優(yōu)先調(diào)用實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor 接口的類的 postProcessBeanFactory方法,再按照先調(diào)用實(shí)現(xiàn)了 PriorityOrdered 接口 再調(diào)用 Ordered 接口 最后再調(diào)用沒有實(shí)現(xiàn) PriorityOrdered 接口 散休、 Ordered 接口 的 BeanDefinitionRegistryPostProcessor 類
  3. 實(shí)現(xiàn)了 InstantiationAwareBeanPostProcessor 接口的類媒楼,調(diào)用 postProcessBeforeInstantiation(Class<?> beanClass, String beanName) 方法,這個(gè)方法可以直接自己初始化出來Bean
  4. 實(shí)現(xiàn)了 MergedBeanDefinitionPostProcessor 接口的類戚丸,調(diào)用 postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) 方法划址;這個(gè)時(shí)候Bean已經(jīng)初始化了,但是屬性還沒有注入限府;AutowiredAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition 找到所有的 @Autowired或者@Value 注解的方法或?qū)傩远岵瑸楹罄m(xù)IOC,依賴注入做準(zhǔn)備
  5. 實(shí)現(xiàn)了EnvironmentAware谣殊、EmbeddedValueResolverAware、ResourceLoaderAware牺弄、ApplicationEventPublisherAware姻几、MessageSourceAware、ApplicationContextAware势告、ApplicationStartupAware的類蛇捌,會(huì)在這一步注入相關(guān)環(huán)境變量屬性
  6. 實(shí)現(xiàn)了 BeanPostProcessor 接口的類,調(diào)用 postProcessBeforeInitialization(Object bean, String beanName) 方法咱台,這一步Bean已經(jīng)實(shí)例化了络拌,并且屬性已經(jīng)注入了,也可以通過這個(gè)拓展來修改對(duì)象
  7. 實(shí)現(xiàn)了 InitializingBean 接口的Bean回溺,會(huì)調(diào)用對(duì)象的 afterSingletonsInstantiated() 方法春贸。一般作為對(duì)象初始化完成調(diào)用的拓展點(diǎn)
  8. 實(shí)現(xiàn)了 BeanPostProcessor 接口的類,調(diào)用 postProcessAfterInitialization(Object bean, String beanName) 方法遗遵,這一步Bean已經(jīng)實(shí)例化了萍恕,并且屬性已經(jīng)注入了,也可以通過這個(gè)拓展來修改對(duì)象
  9. 調(diào)用實(shí)現(xiàn)了 SmartInitializingSingleton 接口類的 afterSingletonsInstantiated() 方法车要;這個(gè)時(shí)候所有的Bean已經(jīng)實(shí)例化完成允粤,后續(xù)加入的Bean不會(huì)受Bean工廠的后置處理器影響
  10. 監(jiān)聽Spring容器啟動(dòng)事件 ContextRefreshedEvent
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翼岁,隨后出現(xiàn)的幾起案子类垫,更是在濱河造成了極大的恐慌,老刑警劉巖琅坡,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悉患,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡榆俺,警方通過查閱死者的電腦和手機(jī)购撼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門跪削,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迂求,你說我怎么就攤上這事碾盐。” “怎么了揩局?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵毫玖,是天一觀的道長。 經(jīng)常有香客問我凌盯,道長付枫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任驰怎,我火速辦了婚禮阐滩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘县忌。我一直安慰自己掂榔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布症杏。 她就那樣靜靜地躺著装获,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厉颤。 梳的紋絲不亂的頭發(fā)上穴豫,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音逼友,去河邊找鬼精肃。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帜乞,可吹牛的內(nèi)容都是我干的肋杖。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼挖函,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼状植!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怨喘,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤津畸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后必怜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肉拓,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年梳庆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暖途。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卑惜。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖驻售,靈堂內(nèi)的尸體忽然破棺而出露久,到底是詐尸還是另有隱情,我是刑警寧澤欺栗,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布毫痕,位于F島的核電站,受9級(jí)特大地震影響迟几,放射性物質(zhì)發(fā)生泄漏消请。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一类腮、第九天 我趴在偏房一處隱蔽的房頂上張望臊泰。 院中可真熱鬧,春花似錦蚜枢、人聲如沸缸逃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽察滑。三九已至打厘,卻和暖如春修肠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背户盯。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工嵌施, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人莽鸭。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓吗伤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親硫眨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子足淆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容