Spring IOC 容器啓動流程分析
使用 Spring 時,XML 和註解是使用得最多的兩種配置方式,雖然是兩種完全不同的配置方式,但對於 IOC 容器來說,兩種方式的不同主要是在 BeanDefinition
的解析上。而對於核心的容器啓動流程,仍然是一致的。
AbstractApplicationContext
的 refresh
方法實現了 IOC 容器啓動的主要邏輯,啓動流程中的關鍵步驟在源碼中也可以對應到獨立的方法。接下來以 AbstractApplicationContext
的實現類 ClassPathXmlApplicationContext
爲主 ,並對比其另一個實現類 AnnotationConfigApplicationContext
, 解讀 IOC 容器的啓動過程。
AbstractApplicationContext.refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
// ...
}
}
ApplicationContext 和 BeanFactory 的關係
ClassPathXmlApplicationContext
和 AnnotationConfigApplicationContext
的繼承樹如下所示。兩者都繼承自 AbstractApplicationContext
。
ApplicationContext 繼承樹(高清大圖)
BeanFactory 繼承樹(高清大圖)
ApplicationContext
是 IOC 容器的承載體,而 BeanFactory
是操作這個容器的工具,兩者關係緊密,相互協作。refresh
方法實現了 ApplicationContext
和 BeanFactory
相互協作的主要過程,不同之處主要在子類 AbstractRefreshableApplicationContext
和 GenericApplicationContext
中實現,兩者使用的 BeanFactory
都爲 DefaultListableBeanFactory
,DefaultListableBeanFactory
的定義如下:
DefaultListableBeanFactory
:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
可見 DefaultListableBeanFactory
實現了 ConfigurableListableBeanFactory
,意味着是可配置,可遍歷的,至於爲什麼可以,讓我們繼續往下尋找找答案。
BeanDefinition 的獲取
DefaultListableBeanFactory
中使用 Map 結構保存所有的 BeanDefinition
信息:
DefaultListableBeanFactory
:
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
ClassPathXmlApplicationContext 中的解析
使用 BeanDefinitionDocumentReader
(可參看 DefaultBeanDefinitionDocumentReader.processBeanDefinition
方法) 將 xml 中的 bean 解析爲 BeanDefinition
, 然後由 BeanDefinitionRegistry
註冊到 BeanFactory
中。
入口:AbstractApplicationContext.refreshBeanFactory
(在 refresh 中調用)
AnnotationConfigApplicationContext 中的解析
通過 BeanDefinitionScanner
掃描 Bean 聲明,解析爲 BeanDefinition
並由 BeanDefinitionRegistry
註冊到 BeanFactory
中。
入口:AnnotationConfigApplicationContext
的構造函數。
爲什麼 ClassPathXmlApplicationContext 的入口是在 refreshBeanFactory 方法中 ?
AbstractApplicationContext.refreshBeanFactory
定義如下:
AbstractApplicationContext
:
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException
可見是一個抽象方法,具體實現在子類中。只有 “Refreshable” 的 BeanFactory
纔會在該方法中實現具體操作,如 AbstractRefreshableApplicationContext
:
AbstractRefreshableApplicationContext
:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
可見 AbstractRefreshableApplicationContext.``refreshBeanFactory
方法會檢查 BeanFactory
是否已經存在(hasBeanFactory
),已經存在就先銷燬所有的 Bean(destoryBeans
)並關閉(closeBeanFactory
) BeanFactory
,然後再創建(createBeanFactory
)新的。
而 GenericApplicationContext.refreshBeanFactory
中會檢查是否爲第一次調用,不是就拋出異常,不執行其他邏輯,即 GenericApplicationContext
不是 "Refreshable"的。
主流程分析
refresh
方法在 AbstractApplicationContext
中定義,其中的 obtainFreshBeanFactory
方法調用了 getBeanFactory
方法,該方法用於獲取 BeanFactory
,這裏爲 DefaultListableBeanFactory
,接下來無特別說明,大部分的方法和變量都將取自 AbstractApplicationContext
和 DefaultListableBeanFactory
。
高清大圖
BeanPostProcessor
BeanPostProcessor
接口讓開發者在 IOC 容器對 Bean 進行實例化時收到回調(postProcessAfterInitialization
和 postProcessBeforeInitialization
方法)。spring 框架內部的許多通知(Aware
)就是通過這個接口實現,如 ApplicationContextAwareProcessor
, ServletContextAwareProcessor
,他們的實現會在 postProcessBeforeInitialization
方法中進行檢查,若實現了特定接口,就會調用 Aware
的回調方法,給予通知:
ServletContextAwareProcessor
:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (getServletContext() != null && bean instanceof ServletContextAware) {
((ServletContextAware) bean).setServletContext(getServletContext());
}
if (getServletConfig() != null && bean instanceof ServletConfigAware) {
((ServletConfigAware) bean).setServletConfig(getServletConfig());
}
return bean;
}
在 postProcessBeanFactory
方法中,子類可以通過 beanFactory.addBeanPostProcessor
方法添加自己的 BeanPostProcessor
到 beanFactory
中,最終將保存到 BeanFactory
的 beanPostProcessors
(實爲CopyOnWriteArrayList
) 中。prepareBeanFactory
和 registerBeanPostProcessors
方法是集中實例化並添加這些 Bean 的地方。
BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor
從"BeanDefinition 的獲取"的介紹可以知道 BeanDefinitionRegistry
用於將 BeanDefinition
註冊到 BeanFactory
中,GenericApplicationContext
和 DefaultListableBeanFactory
都實現了該接口,GenericApplicationContext
中的實現直接調用了 beanFactory
的實現。
BeanFactoryPostProcessor
和 BeanDefinitionRegistryPostProcessor
與 BeanPostProcessor
類似,但從他們的命名就可以看出,所針對的目標不同,分別是 BeanFactory
和 BeanDefinitionRegistry:
1 BeanFactoryPostProcessor
回調讓開發者有機會在 BeanFactory
已經初始化好的情況下對 BeanFactory
的一些屬性進行覆蓋,或是對 beanDefinitionMap
中的 BeanDefinition
進行修改。
2 BeanDefinitionRegistryPostProcessor
則讓開發者可以繼續添加 BeanDefinition
到 BeanFactory
中。
具體邏輯在 invokeBeanFactoryPostProcessors
中實現,這裏首先會將所有實現了 BeanFactoryPostProcessors
的 Bean 實例化,然後調用其回調方法(postProcessBeanDefinitionRegistry
或 postProcessBeanFactory
方法)。
對於這部分 Bean 的實例化和進行回調有一定的優先級規則。PriorityOrdered
繼承自 Ordered
接口,實現了 PriorityOrdered
的 BeanDefinitionRegistryPostProcessor
將最先被實例化並調用,然後同樣的規則來回調實現了 BeanFactoryPostProcessor
的 Bean:
PriorityOrdered
> Ordered
> 未實現 Ordered 的
在 registerBeanPostProcessors
方法中對 BeanPostProcessor
的實例化也有這樣的優先級規則:
PriorityOrdered
> Ordered
> 未實現 Ordered 的 > MergedBeanDefinitionPostProcessor
ApplicationEventMulticaster
在 initApplicationEventMulticaster
中會對 ApplicationEventMulticaster
進行初始化: 首先會檢查是否已經有了ApplicationEventMulticaster
的 BeanDefinition
(在 beanDefinitionMap
中檢查),有就讓容器進行實例化,沒有就使用框架默認的 ApplicationEventMulticaster
(即 SimpleApplicationEventMulticaster
),先實例化,然後註冊到容器中(MessageSource
在 initMessageSource
方法中也是同樣的方式進行初始化)。
事件的起始發送處將事件包裝爲 ApplicationEvent
,並通過 ApplicationEventPublisher
提交給 ApplicationEventMulticaster
,ApplicationEventMulticaster
會將事件廣播給 ApplicationListener
,處理最終的分發。
AbstractApplicationEventMulticaster
中的 applicationListeners(
實爲 LinkedHashSet<ApplicationListener>)
變量保存了所有的廣播接收者,registerListeners
方法會將所有的 ApplicationListener
添加到該集合中。
finishRefresh
方法中有一個對 ContextRefreshedEvent
事件的廣播可以作爲參考,最終事件會由 multicastEvent
方法處理:
SimpleApplicationEventMulticaster.multicastEvent
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
那麼在我們自己的 Bean 中如何得到這個 ApplicationEventPublisher
呢?
ApplicationContext
的定義如下:
ApplicationContext
:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
可見 ApplicationContext
繼承了 ApplicationEventPublisher
,這就說明 AbstractApplicationContext
也是一個 ApplicationEventPublisher
。在我們自己的 Bean 中通過實現 ApplicationEventPublisherAware
,我們就能通過 setApplicationEventPublisher
回調得到 ApplicationEventPublisher
。
上面我們提到 spring 的許多 Aware
是通過 BeanPostProcessor
實現的,ApplicationEventPublisherAware
也不例外:
ApplicationContextAwareProcessor
:
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
// ...
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
// ...
}
IOC 容器在實例化我們的 Bean 時會調用 ApplicationContextAwareProcessor
.postProcessBeforeInitialization
方法,該方法會檢查我們的 Bean,我們的 Bean 如果實現了 ApplicationEventPublisherAware
,那麼就會回調 setApplicationEventPublisher
方法將 applicationContext
(即ApplicationEventPublisher
) 傳給我們,我們就能夠發佈事件。
BeanFactory.getBean
BeanFactory
的幾個重載了的 getBean
方法是 Bean 最終進行實例化的地方,registerBeanPostProcessors
, invokeBeanFactoryPostProcessors
和 finishBeanFactoryInitialization
方法都調用了 getBean 方法對一些特定 Bean 進行了實例化。
finishBeanFactoryInitialization
中通過調用 BeanFactory
的 preInstantiateSingletons
對單例 Bean 進行實例化。BeanFactory
和 BeanDefinition
都具有父子的概念,在子級找不到指定的 Bean 時將一直往上(父級)找,找到就進行實例化
總結
spring IOC 容器的啓動步驟可總結如下:
1 初始化 ApplicationContext
環境屬性的初始化和驗證,啓動時間記錄和相關標記設置,應用事件和監聽者的初始化。
2 準備好容器中的 BeanDefinition (eager-initializing beans)
對 BeanDefinition
的解析、掃描和註冊,BeanDefinition
的掃描和註冊大致可以分爲 XML 和註解兩種,兩種方式各自使用的組件有所不同,該步驟的時間也可以在最前面。
3 初始化 BeanFactory
準備好 BeanFactory 以供 ApplicationContext 進行使用,對接下來將要使用到的 Bean 進行實例化,資源進行準備,屬性進行設置。
4 註冊 BeanPostProcessors
BeanPostProcessors 是進行擴展的關鍵組件,需要在該步驟中進行註冊,可分爲兩種類型: 一種是框架使用者提供的,用於特定業務功能的,另一種是框架開發者提供的,用於擴展框架功能。
5 調用 BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor
是一種功能增強,可以在這個步驟添加新的 BeanDefinition
到 BeanFactory
中。
6 調用 BeanFactoryPostProcessor
BeanFactoryPostProcessor
是一種功能增強,可以在這個步驟對已經完成初始化的 BeanFactory 進行屬性覆蓋,或是修改已經註冊到 BeanFactory
的 BeanDefinition
。
7 初始化 MessageSource
和 ApplicationEventMulticaster
MessageSource
用於處理國際化資源,ApplicationEventMulticaster
是應用事件廣播器,用於分發應用事件給監聽者。
8 初始化其他 Bean 和進行其他的的上下文初始化
主要用於擴展
9 註冊 ApplicationListene
將 ApplicationListene
註冊到 BeanFactory
中,以便後續的事件分發
10 實例化剩餘的 Bean 單例
步驟 4 到 9 都對一些特殊的 Bean 進行了實例化,這裏需要對所有剩餘的單例 Bean 進行實例化
11 啓動完成
資源回收,分發"刷新完成"事件。