- obtainFreshBeanFactory()大体流程
- 1.创建BeanFactory对象
- 2. 解析xml : loadBeanDefinitions(beanFactory)
直接走进核心方法refresh() ,看第一个重要的方法obtainFreshBeanFactory()
![](https://img.haomeiwen.com/i23353704/cbc2e80bf72d2919.png)
obtainFreshBeanFactory()大体流程
1、创建BeanFactory对象,并返回出来
2、xml解析
传统标签解析:bean、import等
自定义标签解析 如:<context:component-scan base-package="com.xiangxue.jack"/>
自定义标签解析流程:
a、根据当前解析标签的头信息找到对应的namespaceUri
b、加载spring所以jar中的spring.handlers文件。并建立映射关系
c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
d、调用类的init方法,init方法是注册了各种自定义标签的解析类
e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
3、把解析出来的xml标签封装成BeanDefinition对象
1.创建BeanFactory对象
1.点进obtainFreshBeanFactory()方法
我们主要看refreshBeanFactory()方法
![](https://img.haomeiwen.com/i23353704/86dcefb78cf76ab8.png)
2.点进refreshBeanFactory(),查看AbstractRefreshableApplicationContext的具体实现
![](https://img.haomeiwen.com/i23353704/c3b19d01162f0c4e.png)
createBeanFactory()
new 了一个DefaultListableBeanFactory 对象,并返回了出来。
![](https://img.haomeiwen.com/i23353704/7af8b4c23edc377c.png)
最后 refreshBeanFactory() 最终返回的BeanFactory 对象也是new 出来的。
customizeBeanFactory(beanFactory);
这个方法设置了BeanFactory的两个属性,默认值是true。
![](https://img.haomeiwen.com/i23353704/1675f7cf77fca9c4.png)
- allowBeanDefinitionOverriding :设置 是否允许BeanDefinition的重写, 这种判断 作用在 xml里面 配置的Bean的id相同的情况下,后面一个会重写前面那个。
- allowCircularReferences :设置是否允许循环依赖。循环依赖 一般指的是 当a实例化时,依赖b, b实例化时又依赖a。常见的有 a,b相互配置了dependOn属性,a,b 互相 属性依赖,还有一种 a,b 构造器参数的相互依赖,这种是无法解决的,spring实例化时会直接抛异常的。
refreshBeanFactory() 该方法剩下的逻辑 是解析xml文件,封装beanDefinition,并注册进BeanFactory中。
2. 解析xml : loadBeanDefinitions(beanFactory)
2.1 将xml文件 解析成 Element对象
![](https://img.haomeiwen.com/i23353704/48e1be10f6b028c9.png)
获取xml文件的路径, 然后委托给解析器 解析
![](https://img.haomeiwen.com/i23353704/7bdf000f762b93d7.png)
遍历解析 配置文件的数组
![](https://img.haomeiwen.com/i23353704/30817850bebc74a2.png)
将xml文件 转化成Resource 对象,
![](https://img.haomeiwen.com/i23353704/140641e66f1f3f05.png)
![](https://img.haomeiwen.com/i23353704/19a53210fb5d6aa8.png)
把resource包成 带编码的
![](https://img.haomeiwen.com/i23353704/997de4001c819a6b.png)
获取resource对象的流,包装成 jdk中 sax xml文件的解析对象 InputSource
![](https://img.haomeiwen.com/i23353704/190861a9d00cccc3.png)
把inputSource 封装成Document文件对象,继续走下去
![](https://img.haomeiwen.com/i23353704/46dd878d857b1784.png)
委托给新创建的BeanDefinitionDocumentReader对象 来解析 document
![](https://img.haomeiwen.com/i23353704/ceccdec734b1892e.png)
解析玩Document之后,就可以 拿到xml文件的root对象,和里面的节点,
![](https://img.haomeiwen.com/i23353704/1cefc564e101f16c.png)
![](https://img.haomeiwen.com/i23353704/65889112d0dac1e0.png)
到这里,xml文件已经解析成 Element对象了, 接下来就是 解析root节点里的子标签了, 比如常见 配置文件里的标签
<!-- 自定义标签-->
<context:component-scan base-package="com.lb.springboot_simple_starter.lookup_method"/>
<!-- 默认标签>
<bean id="a" class="com.lb.springboot_simple_starter.bean.TestInitializing"></bean>
其中对自定义标签和默认标签的处理方式又有所不同。
![](https://img.haomeiwen.com/i23353704/7074e9ec08181012.png)
2.2 默认标签的处理
默认标签有 : import,alias,bean 都会被解析
![](https://img.haomeiwen.com/i23353704/6dd23df3e853f623.png)
2.2.1. Bean标签的解析
这里主要看Bean标签的解析:
- 根据Bean标签的内容创建BeanDefinition
- 将BeanDefinition 注册到 BeanFactory(BeanDefinitionRegistry) 中 , 以后实例化bean用。
![](https://img.haomeiwen.com/i23353704/7bcaacfd126b6928.png)
2.2.1.1 BeanDefinition的创建
![](https://img.haomeiwen.com/i23353704/86ae345a8388c8d9.png)
![](https://img.haomeiwen.com/i23353704/98b10285e9601b75.png)
1. beanName的判断
具体解析 :
先是对id和name属性的解析,判断 beanName的取值
- 如果id有值 ,取id 属性作为beanName
- 如果id 没值,取 name 按 "," 或者 ";" 切割后数组的第一个值 作为 beanName
- 如果id和name都没配置,那么 那么 就 类名 首字母小写作为beanName
![](https://img.haomeiwen.com/i23353704/ae97d015d843e76d.png)
2.parseBeanDefinitionElement 创建BeanDefinition对象
该方法就是创建BeanDefinition对象,然后 根据xml里配置的 填充到BeanDefinition对象 对应的属性中,还有各种子标签也装到bd里中。
![](https://img.haomeiwen.com/i23353704/44e05336d1f9bfde.png)
parseBeanDefinitionAttributes
![](https://img.haomeiwen.com/i23353704/ec64e85c6bf83715.png)
最终,BeanDefination创建完成, 里面的属性和容器 都赋值完成 , 注册到BeanFactory中,后续实例化Bean 再用到这个BeanDefination。
2.3 自定义标签
除非默认标签, import,alias,bean,还有一种自定义标签,
<!-- 扫描该包下的 bean -- >
<context:component-scan base-package="com.lb.springboot_simple_starter.lookup_method"/>
这种的解析方式又有所不同。
回到 解析默认标签平级的另外一个 判断分支上 。
![](https://img.haomeiwen.com/i23353704/053a9f3957e4d1b7.png)
2.3.1 获取对应标签头的处理器 :典型的spi 模式的运用。
![](https://img.haomeiwen.com/i23353704/b75d28a891f1935c.png)
1. 获取所有的handlers
![](https://img.haomeiwen.com/i23353704/58814a02859255b7.png)
如果没有初始化,就从META-INF 下的 spring.handlers 加载
![](https://img.haomeiwen.com/i23353704/4d478bffe2fe90e6.png)
META-INF 下的 spring.handlers
![](https://img.haomeiwen.com/i23353704/d7a12f38f931b908.png)
最终handlerMappings的数据结构是这样的
![](https://img.haomeiwen.com/i23353704/7419722aa3839e54.png)
2. 获取标签头对应的handler
获取到所有的handlerMappings 之后,根据namespace : context 获取到的是ContextNamespaceHandler 类
![](https://img.haomeiwen.com/i23353704/6860d16ae6a7c46c.png)
3. 调用handler.init()方法,注册解析器
然后实例化这个NamespaceHandler,调用init()方法:
往 NamespaceHandlerSupport 的 parsers容器 注册对应 元素的 解析器
![](https://img.haomeiwen.com/i23353704/2de80cd46f183597.png)
![](https://img.haomeiwen.com/i23353704/6966a423e5ce5104.png)
4. 获取对应的解析器, 调用parse进行解析
然后调用NamespaceHandler 父类继承来的 parse方法
![](https://img.haomeiwen.com/i23353704/8e98a67c6ffe8066.png)
![](https://img.haomeiwen.com/i23353704/07532a3aee9efeb7.png)
parse 方法 主要是从 内部的parsers (刚才init()方法已经填充过了) 获取对应的解析器,
![](https://img.haomeiwen.com/i23353704/ad8c0aa72634b830.png)
然后调用 解析器的parse方法。
5.ComponentScanBeanDefinitionParser.parse : 扫包创建BD
这个<context:component-scan 标签 获取到的解析器是ComponentScanBeanDefinitionParser。
该类的ComponentScanBeanDefinitionParser.parse 是用来扫描包, 来查找需要注册的类,创建并注册BeanDefiniation。
![](https://img.haomeiwen.com/i23353704/f395f3f3ba8cb34c.png)
1.ClassPathBeanDefinitionScanner.doScan() 扫包
![](https://img.haomeiwen.com/i23353704/2d81a690101413cb.png)
![](https://img.haomeiwen.com/i23353704/7c788b5ffc7bce23.png)
![](https://img.haomeiwen.com/i23353704/00f39e12b7a20612.png)
2. 判断是否该类是否需要注册
这里判断是否需要注册, 是由内部的 两种类型的过滤器 完成的。
excludeFilters 的match 返回true,则不注册该类,
includeFilters 的match 返回true,就注册该类.
![](https://img.haomeiwen.com/i23353704/ff4cac52cd7e08b1.png)
默认情况下,excludeFilters 是空的,includeFilters 有一个值:
![](https://img.haomeiwen.com/i23353704/5d9ec5bfaf7cfe5a.png)
类上有@Component 注解或者@Component 派生注解,就会被注册。
所以Context:component-scan 标签 的工作原理 就是这样的, 扫描包下的类,判断类上是否有@Component 注解或者@Component 派生注解,有则创建BD注册到BeanFactory中, 后续进行实例化。
3. 注册几个BeanPostProcessor类
![](https://img.haomeiwen.com/i23353704/ab5c226613d19045.png)
![](https://img.haomeiwen.com/i23353704/9f1f5bed2ce9c200.png)
![](https://img.haomeiwen.com/i23353704/dfac29e5fb977980.png)
这里会把 ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor 等类生成BeanDifinition对象,并且在registerPostProcessor方法中,加入到beanFactory中装beanDifinition的容器中。
后续:这几个类会有大用。
网友评论