当前位置: 首页 > article >正文

spring中xml的解析与beanDefinition封装(1)

ClassPathXmlApplicationContext ctx1 = new ClassPathXmlApplicationContext("spring.xml");

今天看下最原始spring解析spring.xml的流程,虽然现在已经不再使用xml去配置bean,而是使用注解类似@Component,@Service等去处理,但是注解的处理与xml解析有很多相似之处,对xml解析流程清楚之后,那么对注解的解析也就很清楚了,所以今天从最原始的ClassPathXmlApplicationContext流程开始看起。

首先会进入到refresh()方法的obtainFreshBeanFactory方法中,在这个方法中可以看到loadBeanDefinitions方法,这里会将spring.xml中配置的所有标签进行解析成beanDefinition。

创建xmlBeanDefinitionReader对象,并通过reader对象加载配置文件

根据加载的配置文件把配置文件封装成document 对象

创建BeanDefinitionDocumentReader 对象,DocumentReader 负责对document 对象解析

parseDefaultElement(ele, delegate);负责常规标签解析

delegate.parseCustomElement(ele);负责自定义标签解析

最终解析的标签封装成BeanDefinition 并缓存到容器中

先看parseDefaultElement方法,这里会去解析<import>,<bean>,<alias>,<beans>标签,我们点进处理<bean>标签的逻辑

可以看到这里主要是做了两件事情,先是将bean标签解析为beanDefinition,然后将beanDefinition注册到BeanDefinitionRegistry中,后面实例化要用到BeanDefinitionRegistry中的beanDefinition

1、创建GenericBeanDefinition对象

2、解析bean标签的属性,并把解析出来的属性设置到BeanDefinition中

3、解析bean中的meta标签

4、解析中的lookup-method标签

5、解析bean中的replaced-method标签

6、解析bean中的construstor-arg

7、解析bean中的property标签

然后再看下parseCustomElement方法

1、获取自定义标签的namespace 命令空间,例如:

http\://www.springframework.org/schema/context

String namespaceUri = getNamespaceURI(ele);

2、根据命令空间获取NamespaceHandler 对象。

NamespaceUri 和NamespaceHandler 之间会建立一个映射,spring 会从所有的spring
jar 包中扫描spring.handlers 文件,建立映射关系。

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

反射获取NamespaceHandler 实例,并调用init()方法

init()方法中会调用registerBeanDefinitionParser方法,可以看到解析component-scan的是ComponentScanBeanDefinitionParser方法

然后再回到最外面的方法,

然后进入到ComponentScanBeanDefinitionParser的parse方法可以看到,这里先是取出<componet-scan>标签的包路径,然后新创建一个ClassPathBeanDefinitionScanner,执行doScan(basePackages)方法去将bean解析为beanDefinition,然后注册到BeanDefinitionRegistry中

我们继续往doScan方法里面看,可以看到findCadidateComponets方法就是扫描到的所有的包路径下的beanDefinition,最终调用registerBeanDefinition注入到容器中

findCandidateComponets处理逻辑如下

1. 首先,通过ResourcePatternResolver获得指定包路径下的所有.class 文件(Spring源码中将
此文件包装成了Resource对象)
2. 遍历每个Resource对象
3. 利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中
MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,
MetadataReader的具体实现类为SimpleMetadataReader)
4. 利用MetadataReader进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选
(条件注解并不能理解:某个类上是否存在@Conditional注解,如果存在则调用注解中所指定
的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉。)
5. 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition
6. 再基于metadataReader判断是不是对应的类是不是接口或抽象类
7. 如果筛选通过,那么就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入结果集
MetadataReader表示类的元数据读取器,主要包含了一个AnnotationMetadata,功能有
1. 获取类的名字、
2. 获取父类的名字
3. 获取所实现的所有接口名
4. 获取所有内部类的名字
5. 判断是不是抽象类
6. 判断是不是接口
7. 判断是不是一个注解
8. 获取拥有某个注解的方法集合
9. 获取类上添加的所有注解信息
10. 获取类上添加的所有注解类型集合
值得注意的是,CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是
利用的ASM技术,并没有加载这个类到JVM。并且,最终得到的ScannedGenericBeanDefinition对
象,beanClass属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object,
它即可以存储类的名字,也可以存储class对象)
最后,上面是说的通过扫描得到BeanDefinition对象,我们还可以通过直接定义BeanDefinition,或
解析spring.xml文件的<bean/>,或者@Bean注解得到BeanDefinition对象。

以上就是<componet-scan>的处理逻辑。

每一个标签会对应不同的handler,具体要看哪个标签的解析,只需要看对应的handler即可

以上就是spring的xml的解析流程,下个章节继续讲解注解形式的解析


http://www.kler.cn/news/362928.html

相关文章:

  • 【哈工大_操作系统理论】L282930 生磁盘的使用从生磁盘到文件文件使用磁盘的实现
  • 精准布局:探索CSS中的盒子固定定位的魅力
  • GEE数据集:1984-2022 年间加拿大 6.5 亿公顷森林生态系统的年度优势树种(也称主要树种)地图
  • 无人机悬停精度算法!
  • kali的下载与配置
  • 在 VS Code 中轻松绘图:Draw.io Integration 插件详解
  • 集成聚水潭·奇门售后单数据到MySQL的技术实践
  • 从“摸黑”到“透视”:AORO A23热成像防爆手机如何改变工业检测?
  • 关于嵌入式学习的一些短浅经验
  • go 语言 Gin Web 框架的实现原理探究
  • 红队-安全见闻篇(下)
  • Vue学习记录之十四 自定义hooks综合实例
  • 成功解决pycharm软件中按住Ctrl+点击指定函数却不能跳转到对应库中的源代码
  • 如何使用 LLM 进行数据分析: 用 5 个步骤为您的数据增压
  • gis中用栅格计算器或加权总和后图层不显示,值也明显不对
  • 企业的图纸一定要加密?10款好用的图纸加密软件保护企业数据!
  • 智能算力中心万卡GPU集群架构深度解析
  • 【某东二面】聊聊 Kafka的分区容错设计思想
  • 《性能之巅:洞悉系统、企业与云计算》读书笔记-Part 1
  • 【rabbitmq】为什么使用消息队列?
  • 促进绿色可持续发展 能源环保管理重中之重
  • 【记录】Android|安卓平板 猫游戏(四款,peppy cat,含下载教程和链接)
  • 大数据新视界 -- 大数据大厂之如何降低大数据存储成本:高效存储架构与技术选型
  • 什么是代理模式?
  • 6.mysql安装【Docker】
  • Redis简介及其在NoSQL应用开发中的优化策略