浅谈Spring中的BeanDefinition的构建

Spring中的类加载

    Spring进行类加载一般是传入一个配置类或者xml文件,然后进行解析。Spring第一步就是把类封装成BeanDefinition,只有把类信息打包进BeanDefinition后,Spring才能实例化bean。接下来就来研究下Spring是如何生成BeanDefinition对象的。

使用XML加载生成BeanDefinition

    spring对xml文件的解析就是对其中标签的解析,解析后生成BeanDefinition。xml的解析入口就是new ClassPathXmlApplication("spring.xml"),进去之后关注refresh方法,构建BeanDefinition的方法就是其中的obtainFreshBeanFactory,如图1:

图1

    获取完实例工厂BeanFactory后,调用的customizeFactory中可以设置是否允许循环依赖和是否允许使用相同名称注册不同的bean实现,之后关注loadBeanDefinitions。接下来开始解析,因为涉及代码比较多,会挑一些重点代码:

1、使用委托者模式把BeanFactory委托给XmlBeanDefinitionReader管理,如图2:

图2

2、通过流的方式解析xml文件,并封装成InputSource对象,如图3:

图3

3、通过jdk的dom4j解析文件,并封装成Document对象,如图4:

图4

4、通过createBeanDefinitionDocumentReader方法获取到BeanDefinitionDocumentReader对象;通过createReaderContext方法获取到XmlReaderContext对象;然后调用registerBeanDefinitions方法,如图5:

图5

5、使用parseBeanDefinition开始对传统标签和自定义标签解析。parseDefaultElement方法用于解析传统标签;parseCustomElement方法用于解析自定义标签,如图6:

图6

传统标签解析

    以bean标签为例,调用的是processBeanDefinition(从代码中也能看到传统标签其实就四种:import、bean、alias、beans),如图7:

图7

    首先通过parseBeanDefinitionElement生成BeanDefinitionHolder,生成该对象需要三个属性:一个是beanName,默认是用id属性;一个是alias别名;一个是最重要的BeanDefinition,通过parseBeanDefinitionElement构建,其中将bean标签的所有属性都注入进了BeanDefinition,如图8:

图8

    然后调用registerBeanDefinition,建立beanName和BeanDefinition之间的映射关系,其次调用registerAlias,建立beanName和alias别名之间的映射关系,如图9:

图9

自定义标签解析

    通过getNamespaceURI获取xml中自定义标签的namespace命名空间,如图10:

图10

    调用handler.parse解析,命名空间的URI和NamespaceHandler之间的映射关系,会从spring源码包里的META-INF文件夹下的spring.handlers文件中找到,比如要解析component-scan标签,parse方法会调用ComponentScanBeanDefinitionParse中的parse方法。spring-context.jar中的spring.handlers,找到ContextNamespaceHandler中的componnet-scan标签对应的实现类,会发现也是ComponentScanBeanDefinitionParse,如图11至图15:

图11
图12
图13
图14
图15

    parse方法关注doScan即可,在findCandidateComponents方法里,把类信息用MetadataReader包装后生成BeanDefinition。虽然这是自定义标签,但是processCommonDefinitionAnnotation方法点进去发现还是有对@Lazy、@Primary等注解的支持,表示注解和xml配置是可以共存的。后面就和传统标签一样生成BeanDefinitionHolder,调用registerBeanDefinition就行了,如图16:

图16

使用配置类加载生成BeanDefinition

    new AnnotationConfigApplicationConext是配置类加载的入口,虽然里面也有refresh方法,但是和xml文件解析不同,生成BeanDefinition却是在register方法中的。

    关注doRegisterBean,在用构造器构建BeanDefinition的时候可以看到同样用了matadata参数把类信息包装了起来:

    这边自然而然也用到了processCommonDefinitionAnnotations方法,来对相应注解的支持,后面又回到了BeanDefinitionHolder相关的代码了,如图17:

图17

BeanDefinition的结构

    用idea的diagrams工具能很清楚地给我们展示接口和类之间的关系(蓝色实现代表类继承,绿色虚线代表类实现,绿色实现代表接口继承),如图18:

图18

从BeanDefinition的实现类图上可以看到AbstractBeanDefinition实现了BeanDefinition接口,且下面有三个子类,分别是:

ChildBeanDefinition:类似于类继承,可以从父类继承构造的参数值和属性值,并且可以重写父类方法,也可以增加新的属性或者方法。

GenericBeanDefinition:从Spring2.5开始引入的一个注册BeanDefinition更好的类,提供了setParentName来动态定义父依赖,可以代替ChildBeanDefinition绝大部分场合。

RootBeanDefinition:可作为一个通用的BeanDefinition来使用,或者是当成上述两个BeanDefinition的父类来使用。

<bean>标签中的属性值

    属性值的含义和使用示例都写在了代码里,后续如果有新的Spring案例也会在这边下载,需要的可以下载:https://github.com/LuoChen1996/my_spring.git

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容