博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码分析
阅读量:6242 次
发布时间:2019-06-22

本文共 9974 字,大约阅读时间需要 33 分钟。

其他更多java基础文章:


Spring源码太大了,对于一个技术不深的我来说,第一次啃会很艰难,于是我决定一个模块一个模块的看,并且将在学习的过程中,觉得很不错的文章记录下来。建议大家先阅读推荐博客,然后再看我的补充。当前Spring版本4.3.18

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()这个方法。

推荐博客

  • :这篇文章阅读顺序非常好,顺着代码运行的顺序,并且有时序图辅助学习,但是单看这一篇,还是有点迷茫,主要是对一些细节方面不够,而且总结也比较粗。应配合下面文章一起学习。
  • :这一系列一共有四章,对细节讲述比较清楚。分成三个模块来讲解,对方法的总结和大白话描述多,更易理解。缺点就是顺序不够好,经常从这跳到另一个地方。

总结

时序图我花时间重新画了一幅,但是流程太长,整条流程保存的画质不怎么好。所以我把整体和局部时序图都画出来,方便大家对比

下面是整个时序图的流转过程文字文字补充:

SpringMain->ClassPathXmlApplicationContext: new ClassPathXmlApplicationContext("applicationContext.xml");ClassPathXmlApplicationContext->AbstractRefreshableConfigApplicationContext: setConfigLocations()AbstractRefreshableConfigApplicationContext->ClassPathXmlApplicationContext: returnClassPathXmlApplicationContext->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 BeanDefinitionHolderDefaultBeanDefinitionDocumentReader->BeanDefinitionParserDelegate: decorateBeanDefinitionIfRequiredDefaultBeanDefinitionDocumentReader->BeanDefinitionReaderUtils: registerBeanDefinitionBeanDefinitionReaderUtils->DefaultListableBeanFactory: registerBeanDefinitionnote 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");复制代码

推荐博客

  • :这篇文章顺序比较好,方便第一次看源码跟着步骤,缺点就是讲的比较少,没有什么总结
  • :这篇文章总结比较多,缺点是是结构顺序好乱,我会在下面补充其顺序

补充

中讲了一个BeanDefinitionParseDelegate #parseBeanDefinitionAttributes方法,该方法的执行位置是在上面读取自定义xml解析的时候,运行到BeanDefinitionParserDelegate #parseBeanDefinitionElement方法时,如下图

流程图

这篇文章的顺序比较混乱,我花时间重新画了下时序图,配合文章阅读更容易理解:

时序图文字补充:

SpringMain-> AbstractBeanFactory: getBeanAbstractBeanFactory-> AbstractBeanFactory#doGetBean: doGetBeanAbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingleton(beanName)AbstractBeanFactory#doGetBean-> AbstractBeanFactory#getObjectForBeanInstance: getObjectForBeanInstanceAbstractBeanFactory#doGetBean-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedLocalBeanDefinitionAbstractBeanFactory#getMergedLocalBeanDefinition-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedBeanDefinitionAbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: registerDependentBeanAbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingletonDefaultSingletonBeanRegistry-> DefaultSingletonBeanRegistry: beforeSingletonCreationAbstractBeanFactory#doGetBean-> AbstractAutowireCapableBeanFactory#createBean: createBeanAbstractAutowireCapableBeanFactory#createBean-> AbstractAutowireCapableBeanFactory#doCreateBean: doCreateBeanAbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#createBeanInstance: createBeanInstanceAbstractAutowireCapableBeanFactory#createBeanInstance-> AbstractAutowireCapableBeanFactory#instantiateBean: instantiateBeanAbstractAutowireCapableBeanFactory#instantiateBean->SimpleInstantiationStrategy: instantiateAbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors: applyMergedBeanDefinitionPostProcessorsAbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors-> AutowiredAnnotationBeanPostProcessor: postProcessMergedBeanDefinitionAutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: findAutowiringMetadataAutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: buildAutowiringMetadataAbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#populateBean: populateBeanAbstractAutowireCapableBeanFactory#populateBean-> AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues: postProcessPropertyValuesAutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> InjectionMetadata: inject.note right of InjectionMetadata: @ResourceAutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: injectnote right of AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: @Autowired&@ValueAbstractAutowireCapableBeanFactory#populateBean-> AbstractAutowireCapableBeanFactory#populateBean: applyPropertyValues复制代码

AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata方法中,Spring会根据注解的不同,例如@Resource或@AutoWired,分别创建不同的类保存返回。这里创建的不同的类会在InjectionMetadata #inject的时候起作用,会调用不同类的inject方法,实现属性的注入。

循环依赖

推荐博客

总结

三层缓存

/** Cache of singleton objects: bean name --> bean instance */private final Map
singletonObjects = new ConcurrentHashMap
(256);/** Cache of singleton factories: bean name --> ObjectFactory */private final Map
> singletonFactories = new HashMap
>(16);/** Cache of early singleton objects: bean name --> bean instance */private final Map
earlySingletonObjects = new HashMap
(16);复制代码
缓存 用途
singletonObjects 用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
earlySingletonObjects 存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
singletonFactories 存放 bean 工厂对象,用于解决循环依赖

这里分别举这样三个例子。 A 依赖 B(B不依赖A)

一级缓存 A 依赖 B && B依赖A

三级缓存 A依赖B && B依赖A + B依赖C && C 依赖 A

转载于:https://juejin.im/post/5cffb72d51882562fb138212

你可能感兴趣的文章
OAF_解决OAF与Windows版本不兼容黑屏
查看>>
如何让编码更加的标准
查看>>
阿里云收集服务器性能指标的python脚本
查看>>
Docker源码分析(一):Docker架构
查看>>
Android开发之在子线程中使用Toast
查看>>
(第三天)函数
查看>>
Git 学习笔记--Git下的冲突解决
查看>>
poj 2955 Brackets(区间dp)
查看>>
jQuery选中该复选框来实现/全部取消/未选定/获得的选定值
查看>>
武汉Uber优步司机奖励政策(8月31日~9月6日)
查看>>
javascript小技巧:同步服务器时间、同步倒计时
查看>>
JUnit4.8.2来源分析-2 org.junit.runner.Request
查看>>
你觉得你在创业,但其实你可能只是在做小生意而已 制定正确的计划 创业和经营小企业之间的差异...
查看>>
HDU 4847-Wow! Such Doge!(定位)
查看>>
冒泡排序算法 C++和PHP达到
查看>>
Android 弹出通知Toast的使用
查看>>
jquery $.each遍历json数组方法
查看>>
jquery access方法 有什么用
查看>>
更改IOS于UISearchBar撤消button底、搜索输入文本框背景中的内容和UISearchBar底
查看>>
WPF XAML之bing使用StringFormat(转)
查看>>