詳解Spring IOC 容器啟動流程分析
使用 Spring 時,XML 和注解是使用得最多的兩種配置方式,雖然是兩種完全不同的配置方式,但對于 IOC 容器來說,兩種方式的不同主要是在 BeanDefinition 的解析上。而對于核心的容器啟動流程,仍然是一致的。
AbstractApplicationContext 的 refresh 方法實現(xiàn)了 IOC 容器啟動的主要邏輯,啟動流程中的關(guān)鍵步驟在源碼中也可以對應(yīng)到獨立的方法。接下來以 AbstractApplicationContext 的實現(xiàn)類 ClassPathXmlApplicationContext 為主 ,并對比其另一個實現(xiàn)類 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 的關(guān)系
ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 的繼承樹如下所示。兩者都繼承自 AbstractApplicationContext 。
ApplicationContext 繼承樹( 高清大圖 )
BeanFactory 繼承樹( 高清大圖 )
ApplicationContext 是 IOC 容器的承載體,而 BeanFactory 是操作這個容器的工具,兩者關(guān)系緊密,相互協(xié)作。 refresh 方法實現(xiàn)了 ApplicationContext 和 BeanFactory 相互協(xié)作的主要過程,不同之處主要在子類 AbstractRefreshableApplicationContext 和 GenericApplicationContext 中實現(xiàn),兩者使用的 BeanFactory 都為 DefaultListableBeanFactory , DefaultListableBeanFactory 的定義如下:
DefaultListableBeanFactory :
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
可見 DefaultListableBeanFactory 實現(xiàn)了 ConfigurableListableBeanFactory ,意味著是可配置,可遍歷的,至于為什么可以,讓我們繼續(xù)往下尋找找答案。
BeanDefinition 的獲取
DefaultListableBeanFactory 中使用 Map 結(jié)構(gòu)保存所有的 BeanDefinition 信息:
DefaultListableBeanFactory : private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); ClassPathXmlApplicationContext 中的解析 使用 BeanDefinitionDocumentReader (可參看 DefaultBeanDefinitionDocumentReader.processBeanDefinition 方法) 將 xml 中的 bean 解析為 BeanDefinition , 然后由 BeanDefinitionRegistry 注冊到 BeanFactory 中。 入口: AbstractApplicationContext.refreshBeanFactory (在 refresh 中調(diào)用) AnnotationConfigApplicationContext 中的解析 通過 BeanDefinitionScanner 掃描 Bean 聲明,解析為 BeanDefinition 并由 BeanDefinitionRegistry 注冊到 BeanFactory 中。 入口: AnnotationConfigApplicationContext 的構(gòu)造函數(shù)。 為什么 ClassPathXmlApplicationContext 的入口是在 refreshBeanFactory 方法中 ? AbstractApplicationContext.refreshBeanFactory 定義如下: AbstractApplicationContext : protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException
可見是一個抽象方法,具體實現(xiàn)在子類中。只有 "Refreshable" 的 BeanFactory 才會在該方法中實現(xiàn)具體操作,如 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 是否已經(jīng)存在( hasBeanFactory ),已經(jīng)存在就先銷毀所有的 Bean( destoryBeans )并關(guān)閉( closeBeanFactory ) BeanFactory ,然后再創(chuàng)建( createBeanFactory )新的。 而 GenericApplicationContext.refreshBeanFactory 中會檢查是否為第一次調(diào)用,不是就拋出異常,不執(zhí)行其他邏輯,即 GenericApplicationContext 不是 "Refreshable"的。
主流程分析
refresh 方法在 AbstractApplicationContext 中定義,其中的 obtainFreshBeanFactory 方法調(diào)用了 getBeanFactory 方法,該方法用于獲取 BeanFactory ,這里為 DefaultListableBeanFactory ,接下來無特別說明,大部分的方法和變量都將取自 AbstractApplicationContext 和 DefaultListableBeanFactory 。
高清大圖
BeanPostProcessor
BeanPostProcessor 接口讓開發(fā)者在 IOC 容器對 Bean 進行實例化時收到回調(diào)( postProcessAfterInitialization 和 postProcessBeforeInitialization 方法)。spring 框架內(nèi)部的許多通知( Aware )就是通過這個接口實現(xiàn),如 ApplicationContextAwareProcessor , ServletContextAwareProcessor ,他們的實現(xiàn)會在 postProcessBeforeInitialization 方法中進行檢查,若實現(xiàn)了特定接口,就會調(diào)用 Aware 的回調(diào)方法,給予通知:
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 都實現(xiàn)了該接口, GenericApplicationContext 中的實現(xiàn)直接調(diào)用了 beanFactory 的實現(xiàn)。
BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 與 BeanPostProcessor 類似,但從他們的命名就可以看出,所針對的目標不同,分別是 BeanFactory 和 BeanDefinitionRegistry: 1 BeanFactoryPostProcessor 回調(diào)讓開發(fā)者有機會在 BeanFactory 已經(jīng)初始化好的情況下對 BeanFactory 的一些屬性進行覆蓋,或是對 beanDefinitionMap 中的 BeanDefinition 進行修改。 2 BeanDefinitionRegistryPostProcessor 則讓開發(fā)者可以繼續(xù)添加 BeanDefinition 到 BeanFactory 中。
具體邏輯在 invokeBeanFactoryPostProcessors 中實現(xiàn),這里首先會將所有實現(xiàn)了 BeanFactoryPostProcessors 的 Bean 實例化,然后調(diào)用其回調(diào)方法( postProcessBeanDefinitionRegistry 或 postProcessBeanFactory 方法)。
對于這部分 Bean 的實例化和進行回調(diào)有一定的優(yōu)先級規(guī)則。 PriorityOrdered 繼承自 Ordered 接口,實現(xiàn)了 PriorityOrdered 的 BeanDefinitionRegistryPostProcessor 將最先被實例化并調(diào)用,然后同樣的規(guī)則來回調(diào)實現(xiàn)了 BeanFactoryPostProcessor 的 Bean: PriorityOrdered > Ordered > 未實現(xiàn) Ordered 的
在 registerBeanPostProcessors 方法中對 BeanPostProcessor 的實例化也有這樣的優(yōu)先級規(guī)則: PriorityOrdered > Ordered > 未實現(xiàn) Ordered 的 > MergedBeanDefinitionPostProcessor
ApplicationEventMulticaster
在 initApplicationEventMulticaster 中會對 ApplicationEventMulticaster 進行初始化: 首先會檢查是否已經(jīng)有了 ApplicationEventMulticaster 的 BeanDefinition (在 beanDefinitionMap 中檢查),有就讓容器進行實例化,沒有就使用框架默認的 ApplicationEventMulticaster (即 SimpleApplicationEventMulticaster ),先實例化,然后注冊到容器中( MessageSource 在 initMessageSource 方法中也是同樣的方式進行初始化)。
事件的起始發(fā)送處將事件包裝為 ApplicationEvent ,并通過 ApplicationEventPublisher 提交給 ApplicationEventMulticaster , ApplicationEventMulticaster 會將事件廣播給 ApplicationListener ,處理最終的分發(fā)。
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 中通過實現(xiàn) ApplicationEventPublisherAware ,我們就能通過 setApplicationEventPublisher 回調(diào)得到 ApplicationEventPublisher 。
上面我們提到 spring 的許多 Aware 是通過 BeanPostProcessor 實現(xiàn)的, 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 時會調(diào)用 ApplicationContextAwareProcessor . postProcessBeforeInitialization 方法,該方法會檢查我們的 Bean,我們的 Bean 如果實現(xiàn)了 ApplicationEventPublisherAware ,那么就會回調(diào) setApplicationEventPublisher 方法將 applicationContext (即 ApplicationEventPublisher ) 傳給我們,我們就能夠發(fā)布事件。
BeanFactory.getBean
BeanFactory 的幾個重載了的 getBean 方法是 Bean 最終進行實例化的地方, registerBeanPostProcessors , invokeBeanFactoryPostProcessors 和 finishBeanFactoryInitialization 方法都調(diào)用了 getBean 方法對一些特定 Bean 進行了實例化。
finishBeanFactoryInitialization 中通過調(diào)用 BeanFactory 的 preInstantiateSingletons 對單例 Bean 進行實例化。 BeanFactory 和 BeanDefinition 都具有父子的概念,在子級找不到指定的 Bean 時將一直往上(父級)找,找到就進行實例化
總結(jié)
spring IOC 容器的啟動步驟可總結(jié)如下: 1 初始化 ApplicationContext 環(huán)境屬性的初始化和驗證,啟動時間記錄和相關(guān)標記設(shè)置,應(yīng)用事件和監(jiān)聽者的初始化。
2 準備好容器中的 BeanDefinition (eager-initializing beans) 對 BeanDefinition 的解析、掃描和注冊, BeanDefinition 的掃描和注冊大致可以分為 XML 和注解兩種,兩種方式各自使用的組件有所不同,該步驟的時間也可以在最前面。
3 初始化 BeanFactory 準備好 BeanFactory 以供 ApplicationContext 進行使用,對接下來將要使用到的 Bean 進行實例化,資源進行準備,屬性進行設(shè)置。
4 注冊 BeanPostProcessors BeanPostProcessors 是進行擴展的關(guān)鍵組件,需要在該步驟中進行注冊,可分為兩種類型: 一種是框架使用者提供的,用于特定業(yè)務(wù)功能的,另一種是框架開發(fā)者提供的,用于擴展框架功能。
5 調(diào)用 BeanDefinitionRegistryPostProcessor BeanDefinitionRegistryPostProcessor 是一種功能增強,可以在這個步驟添加新的 BeanDefinition 到 BeanFactory 中。
6 調(diào)用 BeanFactoryPostProcessor BeanFactoryPostProcessor 是一種功能增強,可以在這個步驟對已經(jīng)完成初始化的 BeanFactory 進行屬性覆蓋,或是修改已經(jīng)注冊到 BeanFactory 的 BeanDefinition 。
7 初始化 MessageSource 和 ApplicationEventMulticaster MessageSource 用于處理國際化資源, ApplicationEventMulticaster 是應(yīng)用事件廣播器,用于分發(fā)應(yīng)用事件給監(jiān)聽者。
8 初始化其他 Bean 和進行其他的的上下文初始化 主要用于擴展
9 注冊 ApplicationListene 將 ApplicationListene 注冊到 BeanFactory 中,以便后續(xù)的事件分發(fā)
10 實例化剩余的 Bean 單例 步驟 4 到 9 都對一些特殊的 Bean 進行了實例化,這里需要對所有剩余的單例 Bean 進行實例化
11 啟動完成 資源回收,分發(fā)"刷新完成"事件。
總結(jié)
以上所述是小編給大家介紹的Spring IOC 容器啟動流程分析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
Java 轉(zhuǎn)型(向上或向下轉(zhuǎn)型)詳解及簡單實例
這篇文章主要介紹了Java 轉(zhuǎn)型(向上或向下轉(zhuǎn)型)詳解及簡單實例的相關(guān)資料,需要的朋友可以參考下2017-02-02
Mybatis-Plus最優(yōu)化持久層開發(fā)過程
Mybatis-plus(簡稱MP)是一個Mybatis的增強工具,在mybatis的基礎(chǔ)上只做增強不做改變,提高效率,自動生成單表的CRUD功能,這篇文章主要介紹了Mybatis-Plus最優(yōu)化持久層開發(fā),需要的朋友可以參考下2024-07-07
java8 stream 操作map根據(jù)key或者value排序的實現(xiàn)
這篇文章主要介紹了java8 stream 操作map根據(jù)key或者value排序的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09
Mybatis配置之<properties>屬性配置元素解析
這篇文章主要介紹了Mybatis配置之<properties>屬性配置元素解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
基于Rest的API解決方案(jersey與swagger集成)
下面小編就為大家?guī)硪黄赗est的API解決方案(jersey與swagger集成)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08

