Spring 應用上下文(ApplicationContext),是 Spring 應用的核心接口,也是我們常說的 Spring 容器,除了擴充了基礎容器 BeanFactory 還提供了更多企業級的特性,如資源管理、事件釋出、國際化等。
前言
Spring 應用上下文(ApplicationContext),是 Spring 應用的核心接口,也是我們常說的 Spring 容器,除了擴充了基礎容器 BeanFactory 還提供了更多企業級的特性,如資源管理、事件釋出、國際化等。了解 Spring 應用上下文的生命周期也就了解了 Spring 内部的運作的核心邏輯,生命周期中同時提供了很多擴充點,跟随文章,我們一探究竟。
應用上下文的生命周期
Spring ApplicationContext 具有層次性的設計,生命周期的管理主要在 AbstractApplicationContext,類圖如下。
生命周期的相關方法均由實作的接口提供,各生命周期階段并非完整地從上而下執行,部分階段是可選的,具體如下。
重新整理階段:org.springframework.context.ConfigurableApplicationContext#refresh
啟動階段:org.springframework.context.Lifecycle#start
停止階段:org.springframework.context.Lifecycle#stop
關閉階段:org.springframework.context.ConfigurableApplicationContext#close
重新整理階段
重新整理階段是 Spring 應用上下文生命周期的主要階段,重新整理階段完成後 Spring 中的非延遲單例 bean 即執行個體化完成,依賴注入也完成,可以正常調用 bean 的方法。有關 bean 的生命周期可參考我前面的文章《Java 面試必備的 Spring Bean 生命周期總結》。
重新整理階段對應的 AbstractApplicationContext#refresh 方法源碼如下。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 應用上下文重新整理準備
prepareRefresh();
// BeanFactory 建立
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// BeanFactory 準備
prepareBeanFactory(beanFactory);
try {
// BeanFactory 後處理,由子類擴充
postProcessBeanFactory(beanFactory);
// BeanFactory 後處理,調用 BeanFactoryPostProcessor 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化 MessageSource
initMessageSource();
// 初始化事件廣播器
initApplicationEventMulticaster();
// 上下文重新整理
onRefresh();
// 注冊事件監聽器
registerListeners();
// 初始化完成,執行個體化所有非延遲初始化的單例 bean
finishBeanFactoryInitialization(beanFactory);
// 重新整理完成
finishRefresh();
} catch (BeansException ex) {
destroyBeans();
cancelRefresh(ex);
throw ex;
} finally {
resetCommonCaches();
}
}
}
下面對應用上下文的重新整理階段進行細化分析。
上下文重新整理準備階段
上下文重新整理準備階段的工作如下:
設定啟動時間及狀态辨別。
初始化 PropertySource。
由子類進行擴充,web 環境下将初始化名稱為 servletContextInitParams 和 servletConfigInitParams 的 PropertySource 。
關于 PropertySource 可參見我前面的文章《Spring 中的 Environment 、Profile 與 PropertySource》。
校驗 Environment 中必須的屬性。
初始化事件監聽器集合。
關于 Spring 事件可參見我前面的文章《Spring 事件處理機制詳解,帶你吃透 Spring 事件》 。
初始化早期事件集合。
對應的AbstractApplicationContext#prepareRefresh方法源碼如下。
protected void prepareRefresh() {
// 設定重新整理事件及激活狀态
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
... 省略日志列印代碼
// 初始化 Environment 中的 PropertySource,該方法為空方法,由子類實作,如 web 環境下添加 ServletContext 初始化及 Servlet 配置的 PropertySource
initPropertySources();
// 校驗 Environment 設定的必須的屬性
getEnvironment().validateRequiredProperties();
if (this.earlyApplicationListeners == null) {
// 首次 fresh,把重新整理前添加的監聽器添加到 earlyApplicationListeners
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
} else {
// 再次 fresh,把之前添加的監聽器添加到 applicationListeners
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 初始化事件集合,事件廣播器初始化完成後釋出
this.earlyApplicationEvents = new LinkedHashSet<>();
}
BeanFactory 建立階段
BeanFactory 建立階段的工作如下:
重新整理 BeanFactory。
銷毀并關閉 BeanFactory,如果已存在。
建立 BeanFactory。
設定 BeanFactory 的 ID。
設定 BeanFactory 是否允許 BeanDefinition 重複注冊及循環引用。
關于循環引用,可參見我前面的文章《Spring 循環依賴處理》。
加載 BeanDefinition。
抽象方法,由子類進行實作。XML 和注解方式加載 BeanDefinition 的方式有所不同。
關于 BeanDefinition,可參見我前面的文章《掌握 Spring 必須知道的 BeanDefinition》 。
關聯 BeanFactory 到應用上下文。
擷取 BeanFactory。
相關的源碼說明如下所示。
// AbstractApplicationContext#obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 先建立 BeanFactory,該方法為抽象方法,由子類進行實作
refreshBeanFactory();
// 再擷取 BeanFactory
return getBeanFactory();
}
// AbstractRefreshableApplicationContext#refreshBeanFactory
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
// 如果已經存在 BeanFactory,先銷毀 bean ,然後關閉 BeanFactory
destroyBeans();
closeBeanFactory();
}
try {
// 建立 BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 設定是否允許重複注冊 BeanDefinition,是否允許循環引用
customizeBeanFactory(beanFactory);
// 加載 BeanDefinition,抽象方法,由子類進行實作
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
BeanFactory 準備階段
BeanFactory 準備階段的工作如下:
設定加載 bean class 的 ClassLoader。
設定解析 BeanDefinition 中字元串的表達式處理器。
添加 PropertyEditorRegistrar 的實作 ResourceEditorRegistrar。
添加 Aware 回調接口 BeanPostProcessor 的實作 ApplicationContextAwareProcessor。
支援的 Aware 回調接口包括 EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware。
忽略 Aware 回調接口作為依賴注入接口。
忽略的 Aware 回調接口和上面 ApplicationContextAwareProcessor 支援的 Aware 回調接口相對應,保持一緻。
注冊 ResolvableDependency 對象作為 bean。
包括 BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。
添加 BeanPostProcessor 的實作 ApplicationListenerDetector。用于将 ApplicationListener 添加到 ApplicationContext。
如果 BeanFactory 中存在名稱為 loadTimeWeaver 的 bean,
添加 BeanPostProcessor 的實作 LoadTimeWeaverAwareProcessor。
設定臨時類加載器 ContextTypeMatchClassLoader。
注冊單例 bean Environment、Java System Properties、OS 環境變量。
相關的源碼說明如下所示:
// AbstractApplicationContext#prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 設定類加載器、表達式處理器;添加 ResourceEditorRegistrar
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 配置 Aware 回調接口的處理器 ApplicationContextAwareProcessor,并且忽略依賴注入對應的 Aware 接口
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 注冊依賴注入時可解析的依賴
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 添加 ApplicationListenerDetector,用于添加事件監聽器到應用上下文
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// AOP 相關
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注冊預設的環境相關的單例 bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
BeanFactory 後置處理階段
BeanFactory 後置處理階段的工作如下:
調用方法 postProcessBeanFactory。
該方法實作為空,由子類進行擴充。
如 web 環境下會設定 ServletContextAware、ServletConfigAware 回調處理,注冊 web 環境下的 scope 及相關的 bean。
調用 BeanFactoryPostProcessor 中的後置處理方法。
如果臨時 ClassLoader 不存在并且存在名稱為 loadTimeWeaver 的 bean,
添加 BeanPostProcessor 的實作 LoadTimeWeaverAwareProcessor。
設定臨時類加載器 ContextTypeMatchClassLoader。
相關的源碼如下:
// AbstractRefreshableWebApplicationContext#postProcessBeanFactory
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加 web 環境下 aware 處理,忽略 aware 依賴注入接口
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
// 注冊 web 環境下的 scope
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
// 注冊 web 環境下的 bean
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
// AbstractApplicationContext#invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 調用 BeanFactoryPostProcessor 處理方法
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// AOP 相關
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
BeanPostProcessor 注冊階段
BeanPostProcessor 注冊階段的工作主要是将 BeanPostProcessor 類型的 bean 添加到 BeanFactory 内部持有的 BeanPostProcessor 清單中。添加順序如下:
實作 PriorityOrdered 接口的 BeanPostProcessor。
實作 Ordered 接口的 BeanPostProcessor。
普通的 BeanPostProcessor。
實作 MergedBeanDefinitionPostProcessor 接口的 BeanPostProcessor。
ApplicationListenerDetector 接口。
相關的源碼如下:
// AbstractApplicationContext#registerBeanPostProcessors
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
MessageSource 初始化階段
MessageSource 初始化階段用于保證 BeanFactory 中存在 MessageSource 類型的單例 bean。關于 MessageSource,可參見我前面的文章《Spring 國際化支援之 MessageSource》。
相關的源碼如下:
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// 設定 messageSource 到目前應用上下文
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// 設定父 MessageSource
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
} else {
// 設定 MessageSource 到目前應用上下文,通過調用父 MessageSource 實作其功能
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
}
}
事件廣播器初始化階段
事件廣播器初始化階段主要用來保證應用上下文中存在 ApplicationEventMulticaster。相關的源碼如下:
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 存在名稱為 applicationEventMulticaster 的 bean,設定到應用上下文
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
} else {
// 不存在 bean,設定到目前應用上下文,并注冊為 bean
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
}
上下文重新整理階段
上下文重新整理階段對應的方法為AbstractApplicationContext#onRefresh,該方法為空方法,由子類進行實作。
事件監聽器注冊階段
事件監聽器注冊階段的工作如下:
添加目前應用上下文關聯的事件監聽器到廣播器。
添加 BeanFactory 中注冊的事件監聽器 bean 到廣播器。
廣播早期事件。
相關源代碼如下:
protected void registerListeners() {
// 添加應用上下文中的事件監聽器到事件廣播器中
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 添加 BeanFactory 中注冊的事件監聽器到事件廣播器中
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 釋出早期事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
// 廣播目前應用上下文重新整理前釋出的事件
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
BeanFactory 初始化完成階段
BeanFactory 初始化完成階段的工作如下:
如果 BeanFactory 中存在注冊的名稱為 conversionService 的 ConversionService,将其設定到 BeanFactory 中。
如果 BeanFactory 中不存在 StringValueResolver,添加 StringValueResolver 到 BeanFactory。
點選檢視原文,擷取更多福利!
https://developer.aliyun.com/article/1086017?utm_content=g_1000365171
版權聲明:本文内容由阿裡雲實名注冊使用者自發貢獻,版權歸原作者所有,阿裡雲開發者社群不擁有其著作權,亦不承擔相應法律責任。具體規則請檢視《阿裡雲開發者社群使用者服務協定》和《阿裡雲開發者社群知識産權保護指引》。如果您發現本社群中有涉嫌抄襲的内容,填寫侵權投訴表單進行舉報,一經查實,本社群将立刻删除涉嫌侵權内容。