Spring源碼分析

其餘更多java基礎文章:
java基礎學習(目錄)java


Spring源碼太大了,對於一個技術不深的我來講,第一次啃會很艱難,因而我決定一個模塊一個模塊的看,而且將在學習的過程當中,以爲很不錯的文章記錄下來。建議你們先閱讀推薦博客,而後再看個人補充。當前Spring版本4.3.18spring

Spring讀取自定義xml文件解析

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
複製代碼

重點

整個容器的啓動流程,都在AbstractApplicationContext的refresh()的模板方法中了緩存

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();
			}

			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.
				destroyBeans();

				// Reset 'active' flag.
				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(); } } } 複製代碼

下面講解的重點是obtainFreshBeanFactory()這個方法。bash

推薦博客

  • 經過源碼閱讀和時序圖來完全弄懂Spring容器:這篇文章閱讀順序很是好,順着代碼運行的順序,而且有時序圖輔助學習,可是單看這一篇,仍是有點迷茫,主要是對一些細節方面不夠,並且總結也比較粗。應配合下面文章一塊兒學習。
  • Spring Ioc 源碼分析(一)--Spring Ioc容器的加載:這一系列一共有四章,對細節講述比較清楚。分紅三個模塊來說解,對方法的總結和大白話描述多,更易理解。缺點就是順序不夠好,常常從這跳到另外一個地方。

總結

時序圖我花時間從新畫了一幅,可是流程太長,整條流程保存的畫質不怎麼好。因此我把總體和局部時序圖都畫出來,方便你們對比app

時序圖(整)

時序圖1

時序圖2

時序圖3

時序圖4

下面是整個時序圖的流轉過程文字文字補充:源碼分析

SpringMain->ClassPathXmlApplicationContext: new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext->AbstractRefreshableConfigApplicationContext: setConfigLocations()
AbstractRefreshableConfigApplicationContext->ClassPathXmlApplicationContext: return
ClassPathXmlApplicationContext->AbstractApplicationContext: refresh()
AbstractApplicationContext->AbstractApplicationContext: obtainFreshBeanFactory()
AbstractApplicationContext->AbstractRefreshableApplicationContext: refreshBeanFactory()
AbstractRefreshableApplicationContext->AbstractXmlApplicationContext: loadBeanDefinitions()
AbstractXmlApplicationContext->AbstractXmlApplicationContext: loadBeanDefinitions()
AbstractXmlApplicationContext->AbstractBeanDefinitionReader: reader.loadBeanDefinitions(configLocations);
AbstractBeanDefinitionReader->AbstractBeanDefinitionReader: counter += loadBeanDefinitions(location);
AbstractBeanDefinitionReader->AbstractBeanDefinitionReader: return loadBeanDefinitions(location, null);
AbstractBeanDefinitionReader->XmlBeanDefinitionReader: int loadCount = loadBeanDefinitions(resource);
XmlBeanDefinitionReader->XmlBeanDefinitionReader: doLoadBeanDefinitions()
XmlBeanDefinitionReader->XmlBeanDefinitionReader: registerBeanDefinitions()
XmlBeanDefinitionReader->DefaultBeanDefinitionDocumentReader: registerBeanDefinitions(doc, createReaderContext(resource));
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: doRegisterBeanDefinitions()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: parseBeanDefinitions()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: parseDefaultElement()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: processBeanDefinition()
DefaultBeanDefinitionDocumentReader->BeanDefinitionParserDelegate: parseBeanDefinitionElement()
BeanDefinitionParserDelegate->BeanDefinitionParserDelegate: parseBeanDefinitionElement(ele, beanName, containingBean);
note right of BeanDefinitionParserDelegate: parsePropertyElements(ele, bd);
BeanDefinitionParserDelegate->DefaultBeanDefinitionDocumentReader: return new BeanDefinitionHolder
DefaultBeanDefinitionDocumentReader->BeanDefinitionParserDelegate: decorateBeanDefinitionIfRequired
DefaultBeanDefinitionDocumentReader->BeanDefinitionReaderUtils: registerBeanDefinition
BeanDefinitionReaderUtils->DefaultListableBeanFactory: registerBeanDefinition
note right of DefaultListableBeanFactory: this.beanDefinitionMap.put(beanName, beanDefinition);
note right of DefaultListableBeanFactory: this.beanDefinitionNames.add(beanName);
DefaultListableBeanFactory->DefaultBeanDefinitionDocumentReader: return 
DefaultBeanDefinitionDocumentReader->AbstractApplicationContext: obtainFreshBeanFactory() is over,return DefaultListableBeanFactory
複製代碼
  • parsePropertyElements(ele, bd);的時候,把類屬性值放入bean中,並返回BeanDefinitionHolder。
  • this.beanDefinitionNames.add(beanName);this.beanDefinitionMap.put(beanName, beanDefinition);時,前者是把beanName放到隊列裏,後者是把BeanDefinition放到map中,到此註冊就完成了。在後面實例化的時候,就是把beanDefinitionMap中的BeanDefinition取出來,逐一實例化

總結來講:

  1. ApplicationContext將解析配置文件的工做委託給BeanDefinitionReader,而後BeanDefinitionReader將配置文件讀取爲xml的Document文檔以後,又委託給BeanDefinitionDocumentReader
  2. BeanDefinitionDocumentReader這個組件是根據xml元素的命名空間和元素名,起到一個路由的做用,實際的解析工做,是委託給BeanDefinitionParserDelegate來完成的
  3. BeanDefinitionParserDelegate的解析工做完成之後,會返回BeanDefinitionHolder給BeanDefinitionDocumentReader,在這裏,會委託給DefaultListableBeanFactory完成bean的註冊
  4. XmlBeanDefinitionReader(計數、解析XML文檔),BeanDefinitionDocumentReader(依賴xml文檔,進行解析和註冊),BeanDefinitionParserDelegate(實際的解析工做)。能夠看出,在解析bean的過程當中,這3個組件的分工是比較清晰的,各司其職

getBean方法

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        JSONArray person = (JSONArray) context.getBean("aaa");
複製代碼

推薦博客

補充

【Spring源碼學習】getBean (上)中講了一個BeanDefinitionParseDelegate #parseBeanDefinitionAttributes方法,該方法的執行位置是在上面讀取自定義xml解析的時候,運行到BeanDefinitionParserDelegate #parseBeanDefinitionElement方法時,以下圖post

流程圖

GetBean源碼全解讀這篇文章的順序比較混亂,我花時間從新畫了下時序圖,配合文章閱讀更容易理解:學習

時序圖文字補充:ui

SpringMain-> AbstractBeanFactory: getBean
AbstractBeanFactory-> AbstractBeanFactory#doGetBean: doGetBean
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingleton(beanName)
AbstractBeanFactory#doGetBean-> AbstractBeanFactory#getObjectForBeanInstance: getObjectForBeanInstance
AbstractBeanFactory#doGetBean-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedLocalBeanDefinition
AbstractBeanFactory#getMergedLocalBeanDefinition-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedBeanDefinition
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: registerDependentBean
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingleton
DefaultSingletonBeanRegistry-> DefaultSingletonBeanRegistry: beforeSingletonCreation
AbstractBeanFactory#doGetBean-> AbstractAutowireCapableBeanFactory#createBean: createBean
AbstractAutowireCapableBeanFactory#createBean-> AbstractAutowireCapableBeanFactory#doCreateBean: doCreateBean
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#createBeanInstance: createBeanInstance
AbstractAutowireCapableBeanFactory#createBeanInstance-> AbstractAutowireCapableBeanFactory#instantiateBean: instantiateBean
AbstractAutowireCapableBeanFactory#instantiateBean->SimpleInstantiationStrategy: instantiate
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors: applyMergedBeanDefinitionPostProcessors
AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors-> AutowiredAnnotationBeanPostProcessor: postProcessMergedBeanDefinition
AutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: findAutowiringMetadata
AutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: buildAutowiringMetadata
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#populateBean: populateBean
AbstractAutowireCapableBeanFactory#populateBean-> AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues: postProcessPropertyValues
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> InjectionMetadata: inject.
note right of InjectionMetadata: @Resource
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: inject
note right of AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: @Autowired&@Value
AbstractAutowireCapableBeanFactory#populateBean-> AbstractAutowireCapableBeanFactory#populateBean: applyPropertyValues
複製代碼

AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata方法中,Spring會根據註解的不一樣,例如@Resource或@AutoWired,分別建立不一樣的類保存返回。這裏建立的不一樣的類會在InjectionMetadata #inject的時候起做用,會調用不一樣類的inject方法,實現屬性的注入。this

循環依賴

推薦博客

總結

三層緩存

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
複製代碼
緩存 用途
singletonObjects 用於存放徹底初始化好的 bean,從該緩存中取出的 bean 能夠直接使用
earlySingletonObjects 存放原始的 bean 對象(還沒有填充屬性),用於解決循環依賴
singletonFactories 存放 bean 工廠對象,用於解決循環依賴

這裏分別舉這樣三個例子。 A 依賴 B(B不依賴A)

一級緩存 A 依賴 B && B依賴A

三級緩存 A依賴B && B依賴A + B依賴C && C 依賴 A

相關文章
相關標籤/搜索