Spring ApplicationContext上下文核心容器深入探究
Spring 容器核心可歸納為兩個類: BeanFactory 和 ApplicationContext,ApplicationContext 繼承自 BeanFactory ,其不僅包含 BeanFactory 所有功能,還擴(kuò)展了容器功能。ApplicationContext 核心其實是 refresh 方法,容器一系列功能都在該方法中實現(xiàn),如:注冊 Bean、注入 Bean 等。
整體流程
refresh 方法定義在 ConfigurableApplicationContext 接口中,被 AbstractApplicationContext 抽象類實現(xiàn),該方法由十幾個子方法組成,這些子方法各司其職完成容器的初始化。
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable { ...... //加載或刷新配置的持久表示形式, //可能是XML文件、屬性文件或關(guān)系數(shù)據(jù)庫模式。 //由于這是一個啟動方法,它應(yīng)該銷毀已經(jīng)創(chuàng)建的單例 //如果失敗,則避免懸而未決的資源。換句話說,在調(diào)用該方法之后,要么全部實例化,要么根本不實例化。 //如果無法初始化bean工廠,則拋出BeanException異常,拋出IllegalStateException異常 //如果已初始化且不支持多次刷新嘗試 void refresh() throws BeansException, IllegalStateException; ...... }
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { ...... @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 準(zhǔn)備此上下文以進(jìn)行刷新 prepareRefresh(); // 告訴子類刷新內(nèi)部bean工廠 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 準(zhǔn)備bean工廠,以便在此上下文中使用 prepareBeanFactory(beanFactory); try { // 允許在上下文子類中對bean工廠進(jìn)行后處理 postProcessBeanFactory(beanFactory); // 調(diào)用在上下文中注冊為bean的工廠處理器 invokeBeanFactoryPostProcessors(beanFactory); // 注冊攔截bean創(chuàng)建的bean處理器 registerBeanPostProcessors(beanFactory); // 為此上下文初始化消息源。 initMessageSource(); // 為此上下文初始化事件多播 initApplicationEventMulticaster(); // 初始化特定上下文子類中的其他特殊bean onRefresh(); // 檢查偵聽器bean并注冊它們 registerListeners(); // 實例化所有剩余的(非懶加載)單例 finishBeanFactoryInitialization(beanFactory); // 最后一步:發(fā)布相應(yīng)的事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 銷毀已創(chuàng)建的單例以避免懸空資源 destroyBeans(); // 重置“活動”標(biāo)志 cancelRefresh(ex); // 將異常傳播到調(diào)用方 throw ex; } finally { // 重置Spring核心中的常見內(nèi)省緩存,因為我們可能不再需要單例bean的元數(shù)據(jù)。。。 resetCommonCaches(); } } } ...... }
在spring中AbstractApplicationContext的實現(xiàn)類通過調(diào)用父類的方法完成容器的初始化,下文以ClassPathXmlApplicationContext為例來追蹤容器的創(chuàng)建流程。
public class contextText { ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean.xml"); }
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { ...... public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } ...... }
refresh 方法中,前四個子方法主要進(jìn)行上下文準(zhǔn)備工作。
prepareRefresh
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 初始化上下文環(huán)境,就是記錄下容器的啟動時間、活動狀態(tài)等 prepareRefresh(); ... } }
public abstract class AbstractApplicationContext { ... private long startupDate; private final AtomicBoolean active = new AtomicBoolean(); private final AtomicBoolean closed = new AtomicBoolean(); private Set<ApplicationEvent> earlyApplicationEvents; ... protected void prepareRefresh() { // 記錄此上下文開始時的系統(tǒng)時間(以毫秒為單位) this.startupDate = System.currentTimeMillis(); // 記錄此上下文是否已關(guān)閉,這里設(shè)置為未關(guān)閉 this.closed.set(false); // 記錄此上下文是否處于活動狀態(tài),這里設(shè)置為活動狀態(tài) this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // 這也是交由子類擴(kuò)展的方法。具體子類為 GenericWebApplicationContext,主要是初始化屬性源, // 將 ServletContext 和 ServletConfig 屬性配置添加到 Environment 環(huán)境上下文中 initPropertySources(); // 校驗 Environment 中那些必備的屬性配置是否存在,不存在則拋異常。 getEnvironment().validateRequiredProperties(); // 創(chuàng)建 ApplicationEvent 事件集合 this.earlyApplicationEvents = new LinkedHashSet<>(); } }
refresh 中的 prepareRefresh 方法執(zhí)行結(jié)束,主要是記錄容器的啟動時間、活動狀態(tài)、檢查必備屬性是否存在。
obtainFreshBeanFactory
public abstract class AbstractApplicationContext { ... public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); ... } } ... protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 該方法也是由子類擴(kuò)展,其子類有 AbstractRefreshableApplicationContext 和 GenericApplicationContext, // 該方法主要設(shè)置 BeanFactory 的 serializationId 屬性值,也就是序列化id refreshBeanFactory(); // 通過 getBeanFactory 返回 BeanFactory 對象。同樣也是由子類擴(kuò)展,調(diào)用的是 GenericApplicationContext 類中的 getBeanFactory 方法。 // 返回的是 DefaultListableBeanFactory 。 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } ... }
obtainFreshBeanFactory 方法很簡單,因為當(dāng)前使用的是ClasspathXmlApplicationContext容器類,從類的繼承關(guān)系可以看出執(zhí)行的就是 AbstractRefreshableApplicationContext 中的 refreshBeanFactory 方法,返回的是DefaultListableBeanFactory,之后該方法還返回了 BeanFactory 對象,從這也可以看出 ApplicationContext 底層是以 BeanFactory 為基礎(chǔ),逐步擴(kuò)展 Spring 容器功能。
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { ...... /** Bean factory for this context */ @Nullable private DefaultListableBeanFactory beanFactory; ...... @Override public final ConfigurableListableBeanFactory getBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory == null) { throw new IllegalStateException("BeanFactory not initialized or already closed - " + "call 'refresh' before accessing beans via the ApplicationContext"); } return this.beanFactory; } } ...... }
prepareBeanFactory
prepareBeanFactory 方法主要是對 BeanFactory 做一些配置,包含各種類加載器、需要忽略的依賴以及后置處理器、解析器等
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... prepareBeanFactory(beanFactory); ... } ... } protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 設(shè)置類加載器 beanFactory.setBeanClassLoader(getClassLoader()); // 設(shè)置表達(dá)式解析器,主要用來解析 EL 表達(dá)式; Bean 初始化完成后填充屬性時會用到 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 設(shè)置屬性注冊解析器,主要用來解析 Bean 中的各種屬性類型,如 String、int 等 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 添加一個后置處理器:ApplicationContextAwareProcessor。 // 該后置處理器用于向?qū)崿F(xiàn)了 Aware 系列接口的 bean 設(shè)置相應(yīng)屬性。 // (后置處理器和 Aware 接口也是比較核心的概念,后面會有文章詳細(xì)討論) beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 以下接口,在自動注入時會被忽略,其都是 Aware 系列接口 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // 當(dāng)以下特殊的 Bean 需自動注入時,指定其注入的類型 。 // 如:注入 BeanFactory 時,注入的類型對象為 ConfigurableListableBeanFactory 。 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 添加 ApplicationListenerDetector 后置處理器。 // 該后置處理器用來檢測那些實現(xiàn)了 ApplicationListener 接口的 bean,并將其添加到應(yīng)用上下文的事件廣播器上。 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 判斷容器中是否存在 loadTimeWeaver Bean,如果存在則上下文使用臨時的 ClassLoader 進(jìn)行類型匹配。 // 集成 AspectJ 時會用到 loadTimeWeaver 對象。 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 注冊和環(huán)境相關(guān)的 Bean,如 environment、systemProperties、systemEnvironment 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()); } }
在 prepareBeanFactory 方法中,主要對 BeanFactory 添加了一系列屬性項,如添加忽略自動注入的接口、添加 BeanPostProcessor 后置處理器、手動注冊部分特殊的 Bean及環(huán)境相關(guān)的 Bean 。
postProcessBeanFactory
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... postProcessBeanFactory(beanFactory); ... } }
postProcessBeanFactory 方法是上下文準(zhǔn)備的最后一步,spring中并沒有具體去實現(xiàn)postProcessBeanFactory方法,是提供給想要實現(xiàn)BeanPostProcessor的三方框架使用的。誰要使用誰就去實現(xiàn)。作用是在BeanFactory準(zhǔn)備工作完成后做一些定制化的處理,一般結(jié)合BeanPostProcessor接口的實現(xiàn)類一起使用,注入一些重要資源(類似Application的屬性和ServletContext的屬性)。最后需要設(shè)置忽略這類BeanPostProcessor子接口的自動裝配。
總結(jié)
ApplicationContext 上下文準(zhǔn)備工作基本結(jié)束,主要還是在 BeanFactory 中添加一系列后置處理器、注冊特殊的 Bean 及設(shè)置忽略自動注入的接口。其中還提到了 Spring 容器的三個核心部分:Aware 系列接口、BeanPostProcessor 后置處理器、BeanDefinition ,這部分在后面的文章會逐步跟蹤。
到此這篇關(guān)于Spring ApplicationContext上下文核心容器深入探究的文章就介紹到這了,更多相關(guān)Spring ApplicationContext內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring系列中的beanFactory與ApplicationContext
- Spring中BeanFactory和ApplicationContext的作用和區(qū)別(推薦)
- ServletWebServerApplicationContext創(chuàng)建Web容器Tomcat示例
- PostConstruct注解標(biāo)記類ApplicationContext未加載空指針
- SpringBoot項目報錯:"Error?starting?ApplicationContext...."解決辦法
- SpringBoot如何使用applicationContext.xml配置文件
- 基于Failed?to?load?ApplicationContext異常的解決思路
- 一文學(xué)透ApplicationContext繼承接口功能及與BeanFactory區(qū)別
相關(guān)文章
基于springboot bean的實例化過程和屬性注入過程
這篇文章主要介紹了基于springboot bean的實例化過程和屬性注入過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11云IDE:Eclipse Che:Eclipse下一代IDE(推薦)
這篇文章主要介紹了云IDE:Eclipse Che:Eclipse下一代IDE,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09java 遍歷request中的所有表單數(shù)據(jù)的實例代碼
下面小編就為大家?guī)硪黄猨ava 遍歷request中的所有表單數(shù)據(jù)的實例代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09java ant包中的org.apache.tools.zip實現(xiàn)壓縮和解壓縮實例詳解
這篇文章主要介紹了java ant包中的org.apache.tools.zip實現(xiàn)壓縮和解壓縮實例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04ReadWriteLock接口及其實現(xiàn)ReentrantReadWriteLock方法
下面小編就為大家?guī)硪黄猂eadWriteLock接口及其實現(xiàn)ReentrantReadWriteLock方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06Java中Lambda表達(dá)式之Lambda語法與作用域解析
這篇文章主要介紹了Java中Lambda表達(dá)式之Lambda語法與作用域解析重點介紹Lambda表達(dá)式基礎(chǔ)知識,需要的朋友可以參考下2017-02-02