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;
与坚持梦想者同行