Spring啟動過程——原始碼分析

風中有朵雲做的雨發表於2019-04-14

前言

Spring是什麼?
Spring發展至今,已經不是簡單的Spring Framework,它包括Spring Data、Spring Boot、Spring Cloud等等組成
不過這裡我們僅討論Spring Framework,重點討論Spring的啟動過程及擴充應用

Spring啟動

監聽器啟動

web.xml配置

Spring啟動過程——原始碼分析
Spring通過監聽器啟動是最常見的方式(後續文章會補上其它啟動方式,如用SpringBoot啟動等)
ContextLoaderListener實現了ServletContextListener,會在web容器啟動的時候呼叫
Spring啟動過程——原始碼分析

Spring啟動過程——原始碼分析
進入initWebApplicationContext()
Spring啟動過程——原始碼分析
這裡只挑重點方法講 this.context = createWebApplicationContext(servletContext);預設會建立一個XmlWebApplicationContext
而後進入configureAndRefreshWebApplicationContext(cwac, servletContext)

Spring啟動過程——原始碼分析
獲取所有需要初始化的配置檔案sc.getInitParameter(CONFIG_LOCATION_PARAM) 也就是上面一開始配置的context-param標籤 最後執行refresh

Spring容器建立過程

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();
			}
		}
	}
複製程式碼

prepareRefresh()

容器refresh預準備工作 AbstractApplicationContext

Spring啟動過程——原始碼分析

  • initPropertySources() AbstractApplicationContext子類自定義屬性設定的方法

  • getEnvironment().validateRequiredProperties() 校驗設定屬性

  • this.earlyApplicationEvents = new LinkedHashSet<>() 儲存容器早期的事件

obtainFreshBeanFactory()

獲取工廠

Spring啟動過程——原始碼分析

  • refreshBeanFactory()

Spring啟動過程——原始碼分析
重點講下 loadBeanDefinitions(beanFactory);
BeanDefinition是工廠中非常重要的屬性,它將所有需要spring管理的bean資訊都儲存起來,會在後邊一個一個去例項化
最終進入

Spring啟動過程——原始碼分析
reader.loadBeanDefinitions(configLocation)方法很深,我看了下,程式碼很深,大致的內容:
根據件用xmlReader去讀取一個個配置檔案 最終呼叫
this.beanDefinitionMap.put(beanName, beanDefinition)

refreshBeanFactory執行完進入getBeanFactory()
直接返回改beanFactory 方法結束

prepareBeanFactory(beanFactory)

Spring啟動過程——原始碼分析
從上往下四個框框作用分別是

  • 在工廠設定類載入器、表示式解析器

  • 給工廠新增ApplicationContextAwareProcessor(processor先不解釋有什麼意思 後續會說明)

  • 設定需要忽略的自動裝配的介面(EnvironmentAware、ApplicationContextAware等Aware)

  • 給工廠新增 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this))

接著上面方法

Spring啟動過程——原始碼分析
最終呼叫

Spring啟動過程——原始碼分析
給容器註冊一些元件

  • environment(ConfigurableEnvironment)
  • systemProperties(Map<String, Object>)
  • systemEnvironment(Map<String, Object>)

postProcessBeanFactory(beanFactory)

BeanFactory準備工作完成後 後置處理
空方法 子類自定義屬性設定的方法 這裡web環境 用的工廠是AbstractRefreshableWebApplicationContext
記住這裡只是web端擴充才有的實現

Spring啟動過程——原始碼分析
這裡先新增了一個ServletContextAwareProcessor和設定需要忽略的自動裝配的介面
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext)
新增了幾個scope

spring本身只有singleton和prototype兩個,web環境加上了request、session、globalSession

invokeBeanFactoryPostProcessors(beanFactory)

這裡沒仔細看

Spring啟動過程——原始碼分析
執行BeanFactory後置處理器 執行這兩種處理器
BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
他們的關係:BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
Spring啟動過程——原始碼分析

Spring啟動過程——原始碼分析
Spring啟動過程——原始碼分析

Spring啟動過程——原始碼分析
Spring啟動過程——原始碼分析
總的來說

  1. 先獲取所有的BeanDefinitionRegistryPostProcessor

  2. 依次執行實現了PriorityOrdered、Ordered介面和沒有實現它們的 processor postProcessor.postProcessBeanDefinitionRegistry(registry)
    在這裡我debug發現 spring內部有一個ConfigurationClassPostProcessor
    它的作用是負責解析處理所有@Configuration標籤類,並將Bean定義(包括其它processor)註冊到BeanFactory中
    這裡註冊完之後 再次獲取所有BeanDefinitionRegistryPostProcessor,按順序執行 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry)
    重點:其它的BeanDefinitionRegistryPostProcessor就是Spring提供給我們註冊bean的通道

  3. 再執行postProcessor.postProcessBeanFactory(beanFactory)

    Spring啟動過程——原始碼分析

  4. 獲取所有的BeanFactoryPostProcessor

  5. 分類執行 執行過的不再執行

Spring啟動過程——原始碼分析
6. 依次執行實現了PriorityOrdered、Ordered介面和沒有實現它們的 processor postProcessor.postProcessBeanFactory(beanFactory)

實踐出真知 這裡是用SpringBoot簡單搭起的一個demo,跟上面不一樣,不過不影響測試結果

Spring啟動過程——原始碼分析

Spring啟動過程——原始碼分析

Spring啟動過程——原始碼分析
執行結果:

Spring啟動過程——原始碼分析
結果在意料之中 也就是說

  • 先執行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry
  • 再執行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory
  • 最後執行BeanFactoryPostProcessor的postProcessBeanFactory

registerBeanPostProcessors(beanFactory)

註冊Bean的後置處理器(跟上面的FactoryPostProcessor不一樣)

Bean的生命週期: Bean建立--初始化--銷燬

不同BeanPostProcessor功能都不一樣
BeanPostProcessor的實現子介面:
DestructionAwareBeanPostProcessor InstantiationAwareBeanPostProcessor MergedBeanDefinitionPostProcessor SmartInstantiationAwareBeanPostProcessor
BeanPostProcessor

Spring啟動過程——原始碼分析

Spring啟動過程——原始碼分析
紅色部分:
獲取所有BeanPostProcessor 依次註冊了PriorityOrdered、Ordered介面、沒有實現它們的、MergedBeanDefinitionPostProcessor
註冊呼叫的是
Spring啟動過程——原始碼分析
黃色部分:
註冊ApplicationListenerDetector :在bean初始化後 檢查如果是listener的話 執行applicationContext.addApplicationListener

initMessageSource()

初始化MessageSource元件(做國際化、訊息繫結、訊息解析)

Spring啟動過程——原始碼分析

  1. 獲取BeanFactory
  2. 檢視容器是否有messageSource的元件
  • 有->this.applicationEventMulticaster beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class)

  • 沒有->new DelegatingMessageSource() 註冊一個MessageSource元件
    beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource)

initApplicationEventMulticaster()

初始化事件派發器

Spring啟動過程——原始碼分析
和上面實現差不多

  1. 獲取BeanFactory
  2. 檢視容器是否有applicationEventMulticaster的元件
  • 有->this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class)

  • 沒有->new SimpleApplicationEventMulticaster() beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster)

這個派發器在後續很有用

onRefresh()

子類自定義的方法 web環境下直接進入一個空方法
還不確定什麼環境下會有執行 歡迎聯絡交流~

registerListeners()

Spring啟動過程——原始碼分析

  1. 獲取所有ApplicationListener
  2. getApplicationEventMulticaster().addApplicationListenerBean
    這裡拿到的派發器就是剛才註冊的
    Spring啟動過程——原始碼分析

finishBeanFactoryInitialization(beanFactory)

較為複雜,單獨作為一篇

finishRefresh()

Spring啟動過程——原始碼分析

  1. 初始化和生命週期有關的後置處理器 initLifecycleProcessor()
  • LifecycleProcessor:
  • void onRefresh();
    呼叫生命週期處理器的onRefresh方法,這個方法會找出Spring容器中實現了SmartLifecycle介面的類並進行start方法的呼叫
  1. 釋出ContextRefreshedEvent事件告知對應的ApplicationListener進行響應的操作
    publishEvent(new ContextRefreshedEvent(this))
  2. 呼叫LiveBeansView的registerApplicationContext方法:如果設定了JMX相關的屬性,則就呼叫該方法 LiveBeansView.registerApplicationContext(this)

相關文章