Spring 源碼(2)Spring IOC 容器 前戲准備工作


Spring 最重要的方法refresh方法

根據上一篇文章 https://www.cnblogs.com/redwinter/p/16141285.html Spring Bean IOC 的創建流程繼續解讀Spring源碼,本篇文章解讀Spring 源碼最重要的方法refresh方法。

這個方法位於:AbstractApplicationContext#refresh,這個方法中總共有15個方法,Spring源碼的精髓就是這15個方法中。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 准備工作,加載環境變量等操作
			// 1、設置容器啟動時間
			// 2、設置停止狀態為false
			// 3、設置活躍狀態為true
			// 4、獲取Environment對象,並設置屬性值
			// 5、設置監聽器和事件的集合,模式為空的集合
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 告訴子類刷新內部 bean 工廠, 獲取刷新bean的工廠: DefaultListableBeanFactory
			// 並且加載BeanDefinition
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 准備BeanFactory 設置一些屬性
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
                 // 允許子類進行擴展BeanFactoryPostProcessor
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 實例化並執行BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 實例化並注冊BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 國際化設置
				initMessageSource();

				// Initialize event multicaster for this context.
				// 實例化事件多播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 初始化特定上下文子類中的其他特殊bean,web容器
				onRefresh();

				// Check for listener beans and register them.
				// 檢查listener bean 並注冊它們
				// 注冊監聽器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 實例化所有剩余的(非惰性初始化)單例。
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 發布相應的事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				// 銷毀Bean
				destroyBeans();

				// Reset 'active' flag.
				// 重置 active 標志
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

前戲准備 prepareRefresh 方法

Spring的前戲准備大概就是做了以下幾件事:

  • 設置容器的啟動時間
  • 設置容器的停止狀態為false
  • 設置容器的激活狀態為true
  • 獲取環境信息並驗證必要的屬性
  • 准備監聽器和事件的容器
protected void prepareRefresh() {
		// Switch to active.
		// 設置啟動時間 設置標識位
		this.startupDate = System.currentTimeMillis();
		// 設置容器停止標識為false
		this.closed.set(false);
		// 設置容器激活標識為true
		this.active.set(true);
		// Initialize any placeholder property sources in the context environment.
		// 初始化上下文環境中的任何占位符屬性源
		// 留給子類進行擴展,比如添加必須的屬性值驗證
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		// 獲取環境對象,並驗證需要的屬性
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		// 准備應用監聽器和實踐的容器初始化
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			// 如果不為空,那么就清空掉,並設置新的早期的監聽器進去
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}
		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

這里有個問題就是他的環境信息是何時設置進去的呢?

實際上是在容器啟動時調用了父類構造函數時設置進去的,Environment他是一個接口,他有個重要的實現類叫StandardEnvironment ,在Spring啟動的時候就會使用這個類進行環境信息的加載,最終他會調用到System#getPropertiesSystem#getenv方法,然后將加載到屬性放在Map中進行保存。

大概的流程如下:

標記的類就是Environment環境信息的加載過程調用的類,最終會調用到System#getPropertiesSystem#getenv方法,然后完成環境信息的加載,主要加載的信息就是系統的環境變量,比如在Windows中配置的環境變量或者啟動類中使用-D參數配置的啟動參數都會進行加載到StandardEnvironment 這個類中,類似於使用-Dxxx.name=123這種參數會加載到systemProperties中,配置的windows環境變量會加載systemEnvironment中。

這個就是Spring IOC 創建的第一個方法的前戲准備工作,接下來解讀默認的BeanFactory實現類DefaultListableBeanFactory的創建過程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM