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:
作用:為配置承載類:ApplicationConfig
ModuleConfig
RegistryConfig
ProtocolConfig
等自動狀態配置
Spring擴展點:BeanPostProcessor