Spring InitBean

Stella981
• 阅读 449

概述

初始化过程

无非是读取->解析->注册,相信程序员都能实现它,但是要把它变成一个框架性的工具还是需要走很多路的。

  1. load 即资源加载,具体说就是找到合适的工具读取合适的资源(不同的方法读取不同的资源,下一篇有详解)

  2. parse 即资源解析,这里的标准比较多,先是根据读取XML中的关键字“DTD”来选择XML资源的校验模式,不知道是不是我代码读错了,我觉得有点土诶;然后根据相对应的实体解析类(这里没仔细研究,但是可以自定义shema标准去拓展)生成DOM;再托管给documentReader去解析DOM生成一个个BEAN;最后代理给BeanDefinitionParserDelegate去解析一个个的BEAN,生成BeanDefinition(这里其实被包装了一下)。

  3. registor 即注册,首先XMLBeanFactory说代理也好,说回调也好,说托管也好,方式都是把自己传下去了,最然过程中自己变样了,从XMLBeanFactory到BeanDefinitionRegistry到XmlReaderContext,最后回到BeanDefinitionRegistry(注意BeanDefinitionRegistry和XMLBeanFactory的区别,而且XMLBeanFactory就逻辑上而言没有传到BeanDefinitionParserDelegate中,虽然代码中有这样写到,具体原因是因为BeanDefinitionParserDelegate只负责将Bean变成BeanDefinition),最后将上一个阶段解析好的BeanDefinition注册到一个MAP中交给XMLBeanFactory来管理。

类图

Spring InitBean

该类的核心是XmlBeanDefinition,该类相关的:左面两个类真是SpringExt拓展的类,提供XSD资源加载策略和Bean的解析策略等;右面两个类可以用第三方替换,旨在提供解析DOM的实现;下面那个类主要是依据DOM解析成一个个的BeanDenifition,主要定义了一些默认的行为。

  • 框架中主要体现的类大致分为三类:控制类、环境类和行为类(control、context、parse/handle)

  • 环境类有三种,分别是:BeanDefinitionRegistry,XmlReaderContext和ParserContext,且都持有BeanDefinition的引用

  • 行为类有:BeanDefinitionParserDelegate,BeanDefinitionParser,NamespaceHandler,EntityResolver

  • 控制类有:XmlBeanDefinitionReader,BeanDefinitionDocumentReader,NamespaceHandlerResolver

详解

从BeanFactory来详解初始化过程,毕竟ApplicationContext的初始化只是一个inner BeanFactory,核心也是利用的BeanFactory来实现的。

XmlBeanDefinitionReader

Spring InitBean

  • resourceCurrentlyBeingLoaded变量的作用:线程本地的变量保存了已经读取的配置文件,以防循环加载(import会触发)

  • 最后的关闭流之前其实流已经被关闭了,因为框架采用了jaxp的dom方式的xml解析,在最后已经被关闭,因此在拓展的时候要注意这一点。

  • 这个类是用来拓展spring的入口点,回顾前面的类图,分析下该类会发现:该类关联了左面两个类,右面两个类和下面一个类。左面两个是用来定义xsd文件的加载策略和解析策略的(正是x3的精髓所在);右面两个类是用来解析xml的,当然你可以哟过sax的解析方法替换之;下面一个类是把解析完的dom二次解析为一个个的BeanDefinition。其实这五个点你都可以替换。

XmlBeanDefinitionReader

Spring InitBean

  • 莫要被这个方法简单的几行所蒙蔽,这三行代码都很值得研究,尤其是第二行,哈哈~这个折腾了我好久,其实最后还是没怎么看懂。

  • 首先是判断文档需要采用dtd验证还是xsd验证,具体实现不难,基于字符验证的。

  • 然后采用jaxp的dom方式来解析xml,getEntityResolver()这个入参既是把我们自定义的dtd/xsd文件的加载策略嵌入进去,所以X3框架的xsd可以采用spring包里面自带的,也可以采用webx3-core里面自带的,也可以采用工程meta目录下面的,大家有兴趣的可以去看看。

XmlBeanDefinitionReader

Spring InitBean

  • 构建dom解析的上下文:xmlReaderContext,因为持有NamespaceHandlerResolver因此就具有解析成BeanDefinition的能力,有个细节注意下,此上下文依旧持有BeanDefinitionRegister的引用,为的就是最后的注册

  • 这个方法是第二个拓展点:NamespaceHandlerResolver的入口点

BeanDefinitionDocumentReader

Spring InitBean

  • 拓展点很明显,是前置处理器和后置处理器

  • 创建了个代理去解析dom,其实这也是一个control-action的模型,BeanDefinitionDocumentReader处理的是dom树,而代理处理的是每一个节点,因此具体的实现都是在代理类之中。

BeanDefinitionDocumentReader

Spring InitBean

  • 默认的命名空间和自定义的命名空间的解析方式差距还是挺大的,默认的用不到NamespaceHander,具体的解析实现都在BeanDefinitionParseDelegate中;自定义的命名空间的BeanDefinition的解析过程:NamespaceHandlerResolver解析出具体的NamespaceHandler,然后依据该handler取出具体的BeanDefinitionParser来解析一个个element元素

  • 哪些是默认的命名空间,哪些是自定义的命名空间呢?是不是我们自己写的哪些xsd算是自定义呢?其实仅仅http://www.springframework.org/schema/beans该命名空间是默认命名空间,其他的均为自定义,诸如aop之流都属于自定义范畴,可以去看下spring的jar包中的spring.handler文件(x3框架没有该文件的原因是x3框架只有一个handler)

  • NamespaceHandler的理解:spring中的涵义为,管理一个命名空间下的所有parsers;但是X3中不一样,X3中自定义很多命名空间,但是只有一个hander,因此x3框架中的涵义可以理解为,管理所有拓展点的parsers。

BeanDefinitionParseDelegate(自定义命名空间的解析)

Spring InitBean

  • spring默认的NamespaceHanderResolver会读取meta/spring.handler,依据namespaceUri取得相应的hander

  • 生成解析所需要的上下文:ParserContext(持有BeanDefinitionRegister,解析完要注册的嘛)

  • X3框架就有很多parsers,都是继承的该类

BeanDefinitionDocumentReader(默认命名空间的解析)

Spring InitBean

  • 注册方法放在工具类中,因为很多地方会触发该注册行为

  • 装饰不知对应的何功能?

BeanDefinitionParserDelegate

Spring InitBean

  • 为何要包装一下,见注释

BeanDefinitionParserDelegate

Spring InitBean

  • BeanDefinition首次出现在了这个类中,标注下

BeanDefinitionDelegate

Spring InitBean

  • 举个解析bean节点的所有property属性来说明吧

BeanDefinition.parsePropertyValue(…)

Spring InitBean

解析map的例子

Spring InitBean

  • 返回的是个map,不知道getBean的时候是怎么处理的,待后续研究

  • BeanDefinition阶段的属性值的转化是在getBean的时候处理的,这个也值得研究,比如X3框架中ParserRequestContext对传递的参数做类型转换也用到了这个功能点,在学习getBean的时候深入下

涉及到的相关功能点

XML解析

由于时间比较仓促,就概要性的介绍下,主要是自己学习过程中的疑惑

  • 有图有真相,先来两张典型的图

Spring InitBean

Spring InitBean

  • XML验证的时候需要一个验证文件,XSD或者DTD,但是需要一个PublicId和SystemId,网上的说法众说纷纭,参照spring的实现,我的理解是这样的:首先,PublicId和SystemId指的都是XML文件的外部引用,只不过前者大家的认知度更高一点,后者更加私有一点;其次,他们表达的都是验证文件的位置,在DTD中如果是PUBLIC的话需要指明详细地址(就是第二个参数),如果是SYSTEM的话就不需要用简称了,但是在XSD中并没有这个概念;最后,在代码中需要传入PublicId和SystemId,对于DTD都应该知道对应的是什么,但是XSD中Public为null,具体的url为SystemId

  • 验证文件填写的网络地址是不是每次验证都需要去下载呢?这就要看EntityResolver了,一般都是优先从本地加载,这是一个策略模式的应用

  • 验证XML都干了哪些事情:验证文档的合法性和填充一些默认的值。

  • 大致是如何解析XML的:主要有两种解析xml的方法,DOM和SAX,前者将xml整个载入内存,然后遍历每个节点,读取对应的验证文件进行验证;后者主要针对于xml过大的情况,它是事件驱动的方式来完成xml的解析,并且是分批次的读入XML来解析,因此存在无法修改的弊端

  • 解析XML和验证XML是如何交互的:首先,解析XML,当发现当前读取节点的命名空间的xsd没有加载的时候,加载该xsd,生成了一个dom语法,然后依据该语法验证该节点,当验证通过之后继续解析。

SpringExt相关

其实和springExt相关的实现已经嵌入到了前面了,这里就简单贴两张图,加深下理解

  • 流程图

Spring InitBean

  • 主体实现类

Spring InitBean

Spring InitBean

  • X3框架是如何嵌入自己实现的XmlApplicationContext

Spring InitBean

Spring InitBean

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
3年前
Eclipse插件开发_学习_00_资源帖
一、官方资料 1.eclipseapi(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fhelp.eclipse.org%2Fmars%2Findex.jsp%3Ftopic%3D%252Forg.eclipse.platform.doc.isv%252Fguide%2
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这