Spring源码学习——解析xml节点

核心文件:BeanDefinitionParserDelegate

  • 以下内容为本人有道笔记内容迁移

1:处理默认节点

DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions用来处理解析出来的dom元素;针对4个默认的标签走parseDefaultElement方法(beans,bean,alias,import)

1.1 bean节点

  • 入口:BeanDefinitionParserDelegate.processBeanDefinition方法

1.1.1转换为beanholder

  • 入口:BeanDefinitionParserDelegate.parseBeanDefinitionElement方法
1.1.1.1 :校验beanname是否在set中存在,并且将beanname放入一个set缓存,其中包含所有已经处理过的bean的name;
  • 入口:BeanDefinitionParserDelegate.checkNameUniqueness

1.1.1.2 通过element创建beandefinition(核心)

入口:BeanDefinitionParserDelegate.parseBeanDefinitionElement方法

1.1.1.2.1:创建abstractbeandefinition
  • 入口:BeanDefinitionParserDelegate.createBeanDefinition(className, parent)
  • 实际执行方法:
    BeanDefinitionReaderUtils.createBeanDefinition:创建GenericBeanDefinition实体,设置beanclass返回

1.1.2 decorateBeanDefinitionIfRequired

  • 装饰bean,默认标签下不做深入解析
  • 查看后发现,对于默认标签没有处理,非默认标签需要获取对应的handler之后调用他的decorate方法

1.1.3 registerBeanDefinition

  • 注册bean到beanfactory
    -实质上是调用beanfactory的registerBeanDefinition方法(默认为DefaultListableBeanFactory)
  • 进入方法后可以看到:首先通过beanname从一个名为beanDefinitionMap的ConcurrentHashMap中查询是否存在(debug发现beanname来自于id或name,如果没有设置则用class加上#序号作为beanname)
1.1.3.1:如果不在beanDefinitionMap中并且beanfactory还没开始创建bean

1)加入beanDefinitionMap
2)加入beanDefinitionNames(arraylist)
3)移除手工添加的单例bean

如果已经开始创建bean:
1)加入beanDefinitionMap
2)将beanDefinitionNames(arraylist)移入一个新的arraylist并加入该条
3)移除手工添加的单例bean

1.1.3.2:如果在beanDefinitionMap中

首先判断beanfactory是否允许复写(override),如果允许则直接覆盖写入beanDefinitionMap。

bean节点解析完成:最终创建的beandefinition放在了map中,内部还有一个arraylist存放beanname

2:处理非默认节点(重点)

  • 入口:BeanDefinitionParserDelegate M:parseCustomElement

2.1 context:component-scan

  • 解析非默认节点的处理方法:BeanDefinitionParserDelegate内
  • 每个类型节点对应的解析类,在对应jar包的META-INF/spring.handlers目录下定义;

2.1.1 获取解析该类节点的handler

  • 以context为例,对应的contextjar包下指明他的解析类为ContextNamespaceHandler,通过resolve方法直接获取handler的实例;

2.1.2 获取该节点明细的parser

  • 通过handler的init方法,定义该namespace下的明细节点处理类,放在map缓存。本例为ComponentScanBeanDefinitionParser

2.1.3 通过获取的parser解析该节点

  • 在doScan方法中将扫描出来的bean注册;
    registerComponents中注册多个BeanPostProcessor接口实现类,供后续spring调用统一接口进行解析

通过base-package属性,解析到机器上的class的实际绝对地址根路径

如果是jar包,则通过扫描器Scanner对jar进行解析,获取class;

解析获取到所有的class之后,通过typefilter过滤等,剩下满足条件可以被处理为bean的class;

posted @ 2020-06-04 21:50  快乐肥宅  阅读(192)  评论(0编辑  收藏  举报