OverView
Java程序員都應清楚Spring生命周期,這是Java程序員的基礎知識。牢牢掌握這些知識點這不僅僅可以應付面試,更重要的是,可以更好的分析實際工作中的問題。
本文將把SpringBoot、Spring、Dubbo結合起來,分析他們的啟動流程。整個過程大致會長下面這個樣子。

下面,我們就分別看看SpringBoot的啟動過程。
SpringBoot的啟動過程
SpringBoot可以理解為Spring的啟動程序,啟動程序的入口方法為SpringApplication.run(),詳細如下:

A: 通知 Listener,start
B: 創建Enviroment,Enviroment是整個應用的配置以及Profile的承載類
C: 創建容器
D: 初始化容器, ApplicationContext.refresh()即為容器初始化入口
E: 空方法
F: 通知 Listener,started
G: 通知 Listener,running
通過觀察發現:SpringBoot.run()中代碼步驟,大致可以歸納總結為兩種行為動作:
SpringApplicationRunListeners調用(藍色)- 創建和初始化容器(綠色)兩部分
所以個人覺得SpringApplicationRunListeners代表了SpringBoot的生命周期,這個生命周期描述了SpringBoot的啟動過程,如:創建初始化Enviroment,創建初始化容器
總結:SpringBoot的生命周期,如下圖:

Spring啟動過程
在SpringBoot啟動過程中,會創建、刷新ApplicationContext。結合上面的流程后,如下圖:

這里的refreshContext,就是Spring容器創建初始化的過程,下面我們詳細介紹一下此過程。
Spring中有一個類AbstractApplicationContext,所有類型的ApplicationContext,例如ClassPathXmlApplicationContext,FileSystemXmlApplicationContext AnnotationConfigApplicationContext 都是繼承此類。
AbstractApplicationContext 中有一個著名的方法refresh(),Spring容器的設計者們將容器啟動過程抽象到了這個方法中,也就是AbstractApplication.refresh()方法中。 所有類型的ApplicationContext都會進入此方法。

Dubbo的啟動過程
Dubbo程序是以Spring Beans的形式存在於Spring容器中,隨着Spring容器啟動而啟動。
對於Dubbo業務方來說,主要有兩個重要的Bean,ServiceBean和ReferenceBean,他們各自會調用Service.export()和Reference.get()來暴露服務以及引用遠程服務。
在使用這兩個Bean的時候,Dubbo的設計者為了讓用戶可以以Annotation的方式方便的使用,他們利用Spring的眾多擴展點,在Spring容器啟動過程中,自動發現、注冊、實例化了ServiceBean與ReferenceBean。
具體流程圖如下:

BeanDefinition的注冊
EnableDubbo:
如果我們是使用Annotation方式使用Dubbo,那么會在SpringConfig類中添加@EnableDubbo注解,這個注解會利用@Import注解的BeanDefinition注冊機制,向容器中注冊DubboConfigBindingBeanPostProcessor ServiceAnnotationBeanPostProcessor ReferenceAnnotationBeanPostProcesser這三個重要的postProcessor來完成ServiceBean與ReferenceBean的創建。
@Import注解是由下面的ConfigurationClassPostProcessor讀取執行的。
ConfigurationClassPostProcessor:
Spring在容器的refresh()方法執行過程中,當BeanFactory准備好后就會執行invokeBeanFactoryPostProcessors(BeanFactory),如果debug源碼會發現剛開始候容器只有ConfigurationClassPostProcessor 這一個BeanFactoryPostProcessor,它的作用,按照源碼的說法是:Bootstrapping processing of @Configuration 。源碼注解大概意思是:它是第一個加載進容器並被執行的BeanFactoryPostProcessor,然后他作為Configuration引導過程,自動導入程序中的其他Configuration相關類。
原來,@Configuration @Import就是由它讀取執行的。
ServiceAnnotationBeanPostProcessor:
時機:
ServiceAnnotationBeanPostProcessor是一個BeanFactoryPostProcessor在容器invokeBeanFactoryPostProcessors()過程中,會被執行。
作用:以@Service作為過濾條件,掃描指定scanBasePackages,向容器注冊ServiceBean。在refresh完成的時候,會向容器中發送ContextRefershEvent,ServiceBean實例會監聽此事件,然后執行服務export過程。
擴展點:BeanFactoryPostProcessor
Bean初始化
ReferenceAnnotationBeanPostProcessor:
時機:
- 在容器初始化完成后,會實例化容器中的單例非懶初始化Bean。
- 在實例化Bean以后,初始化Bean屬性前會調用populateBean()方法,執行
AnnotationInjectedBeanPostProcessor為注入依賴的屬性。 - 而
ReferenceAnnotationBeanPostProcessor就是繼承自AnnotationInjectedBeanPostProcessor,此時它會隨着一起執行。
動作:
- 加載掃描目錄
scanBasePackages下的類,找到@Reference所注解的字段,為其注入值。 - 注入的值為業務接口的動態代理類,動態代理(InvocationHandler)的邏輯是調用
ReferenceBean.get()方法,創建真正的Invoker。 - 所以最終注入了封裝了遠程調用邏輯的
Invoker
Sping擴展點:BeanPostProcessor AnnotationInjectedBeanPostProcessor
DubboConfigBindingBeanPostProcessor:
作用:為配置承載類:ApplicationConfigModuleConfig RegistryConfig ProtocolConfig等自動狀態配置
Spring擴展點:BeanPostProcessor
