spring源码解析 – spring容器加载源码(beandefinition封装和注册过程)

前言

一直听说spring对java进行了重定义,设计和封装体系比较宏大;加上最近遇到了spring的问题,为了更好地定位问题,最近一段啃了一下spring源码。我用的源码T P W版本是5.2.28,下面就把最近的研究成果做一下分享。

我的源码阅读目标主要是IOC和AOP这两块,先来看看spring容器加载这块
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
我们重点来分析一下前两种容器加载方式。至于嵌入式容器加载方式,后续接触到SpringBoot时再介绍。
虽然现在spring boot大行其道,但就底层的实现来讲很多都是J p ~ 8 r ) e g @基于springframework来实现的。所以我们由必要分析一下通过j ( @ Fxml方式加载容器方式。注解方式容器加载方式作为当前主流m c ( : ; U )同样也是分析的重点(其实它们在执I [ & 3行流程上有很多相同的处理环节)。
先来整体看看这两种方式的容器加载流程

容器加载流程

spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
注:流程中标记的环节是接下来要陆续分析的重点
从以上两种方式容器加载的流程我们可以看到,从整体上讲,xml配置解析方式只比注解扫描方式多了一个xml解析的环节,解M - 7 }析的结果最终1 p . * . ; 3还是要封装和注册beandefinition对象。另外注解扫描方式会把三大组件的注册@ , l G W B j -、包的扫描环节提前完成。OK,t ~ = 接下来我们一个一个来看。

xml配置H O | N : + Y ~ )解析

容器入口
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
容器上下文刷新refresh()入口
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
AbstractP S ^RefreshableApplicationContext.refreshBeanFactory()模板方法
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
AbstractXmlApplicationContext.% k P C 8loadBeanDefinitions()解析配置核心方法
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
将配置资源封装成In} z X % F c N M bputSU M . A A U 3tream流对象
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
BeanDefiM : #nitionDocumentReader.registerBeanDefa } C 9 u Linitions()解析和注册bea1 V l tndefinition入口方法
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
DefaultBeanDefinitioC A S H } Z C M jnDocumentReader.parseBeanDefinitions()核心解析方法
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
DefaultBeanDefinitionDocumentReader.parseDefaultEP B ! Y V l ; L qlement()默认标签解析过程
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
解析中间结果包装BeanDef r ^ c ; 5 ?initionHolder包装对象
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
BeanDefinitionPl $ = AarserDelegate.parseBeanDefinitionElement()解析bean标签的各种属性 3 z # )和子元素
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
通用beandefinition数据结构
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
BeanDefinitionParse# D } ` C @ . Prq ( _ 8Delegate.decorateBeanDefinitionIfRequired()装饰beandefinition其它功能
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
这种装饰器模式在自定义标签解析有使用
BeanDefinitionReay l xderUtils.registerBeanDefinition()注册beandefinition工具类方法 . {
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
BeanDefinition注册的目标接口Bea* O J 0 8 W tnFactory--->DL w s d GefaultListableBeanFactory对象
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
BeanDefiL l | x N VnitionParserDelegate.& _ 5 / mparseCustomElement()解析自定l ! G 9 N W义标签
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
以上的handlers的解析对于spring来源说有7 n J s很多c ^ 5 1 = s I f u,我们也可以自定义标签对象,以内置的context标签为例,包含以下部分
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
Cop . C X v g % (mponentS_ 3 S $ HcanBeanDefinitionParser.parse()解析<context:component-# M i J D Z d ;scan/>标签解析过程
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
创建ClassPathBeanDefinitionScanner扫描器
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
ClassPathScanningCandidateComponentProvider.registerDefaultFilters( O 3()注册默认{ q ^的注解类型过滤器
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
ClassPathBeanDefinitionScanner.doScan()包class文件Z Q f 1扫描

注解扫描

AnnotationConfigApplicationContext构造函数注解扫描入口
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
AnnotationCu P wonfigUtils.registerAnnotationConfigProcessors()注册三大组件,过程同xml解析中组件注册相同
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
ClassPathBeanDefinitionScanner扫描器注册和NamespaceUri处理器
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
ClassPathB2 K ? EeanDefinitionScanner.scan()执行包扫描
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
AbstractApplicationContext.refresh()容器上下文刷新, 同xml配置解析加载类似
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)
注解扫描重写GenericApplicationContext.refreshBeanFactory()方法(没有重要实现);x8 S $ G Vml配置解析重写的是:AbstractRefreshableApplicationContext.refreshBeanFactory()方法(核心实现就在此);
refresh()容器刷新的后续步骤,两h ~ s种以上两种容器加载方式都相同,+ 2 1 ! ~ = & S A这里就不再赘述 。R 4 ` a _

调用时& v L X W

最后,让我们来梳理一下xml配置解析和注解扫描3 ) X两种方式的beandefinition封装和注解过程
xml配置解析和注册be6 5 w t { W k G iandefinition调用时序

总结

至此两种容器加载方式的beandefinition封装和注册过程就介绍完毕J Y 6 1 0 V a 9 K了,有任何关于这块的问题欢迎在下方留言!下次我们重点解析bean实例化过程。更多spring源码干货请继续关注!