试读Spring源码(二)BeanDefinition的加载

Spring容器对BeanDefinition的加载是定义在AbstractApplicationContext的refreshBeanFactory方法中,具体实现是在AbstractRefreshableApplicationContext子类。

Spring容器,在实例化DefaultListableBeanFactory后,开始加载BeanDefinition,其加载方法是loadBeanDefinitions(beanFactory)。这里以XmlWebApplicationContext为例子,看Spring容器是如何加载BeanDefinition。

首先是创建XmlBeanDefinitionReader实例。在创建该实例时,会将BeanFactory作为构造参数传进来,同时会将容器的一些属性设置进来,如Environment、ResourceLoader、EntityResolver。随后执行占位方法initBeanDefinitionReader,该方法默认无具体操作。然后调用loadBeanDefinitions的重载方法,传入ApplicationContext的配置文件,然后继续调重载方法,直至将配置文件加载为EncodedResource。

在处理成Resource后,XmlBeanDefinitionReader会通过doLoadDocument方法,将配置文件处理为Document对象。然后通过registerBeanDefinitions方法,对Document做进一步的处理。在这里,还会实例DefaultBeanDefinitionDocumentReader对象用来注册BeanDefinition。这里有一个需要注意的地方是,BeanFactory通过构造参数引入到XmlBeanDefinitionReader,然后

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

通过这个createReaderContext方法,将BeanFactory引用到XmlReaderContext中,从而达到DefaultBeanDefinitionDocumentReader中存在BeanFactory的引用,然后将BeanDefinition注册到BeanFactory上。然后继续通过

doRegisterBeanDefinitions方法,对配置文档里面的元素进行处理。

doRegisterBeanDefinitions方法可看出,Spring的配置文件存在多个层级节点。这个方法递归执行,首先从根节点出发,父节点默认为null,通过delegate来引用父节点。这个delegate引用主要是用于设置一些默认值例如default-lazy-init,default-merge,default-autowire等等,采用的策略都是如果不为空则设置相应的值,如果为空则设置为默认值,通过delegate可保证每个子节点不存在默认值时,其默认值都是其存在设置默认值且最为靠近的父节点的默认值。这个有点绕,其实就是当子节点不存在默认值时,会从父节点找,直至找到存在有相应默认值的父节点。如果一直没有,则是Spring设置好的默认值。设置完默认值后,同样存在两个占位方法preProcessXml,postProcessXml用以对Xml元素做进一步处理。

parseBeanDefinitions方法则主要是将具体的节点转化为BeanDefinition。在这里根据节点名称,做不同的处理,这里主要看了BEAN_ELEMENT节点,这里通常就是我们定义Bean的地方,主要逻辑在于parseBeanDefinitionElement这个方法中。该方法首先是拿到节点的Id和name属性,就是对应的Bean的Name和别名。这里可以看出,获取Bean的Name应该是配置文件里的Bean节点的Id,而节点的Name属性则是别名,当节点不存在Id属性时,则取第一个别名。然后就是创建GenericBeanDefinition,根据节点信息,设置其相应的属性,然后再将其同BeanName和别名一起封装为BeanDefinitionHolder返回。这样一个BeanDefinition就初步加载好了。当然下面还可以通过NamespaceHandler对初步加载好的BeanDefinition做进一步的修饰。Spring的扩展性,是真的好。加载好后的BeanDefinition通过

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());将其注册到BeanFactory上。

此外,上面提到doRegisterBeanDefinitions这个方法是一个递归方法,其递归主要是在于当parseBeanDefinitions方法遇到NESTED_BEANS_ELEMENT节点名称,也就是内嵌的beans节点,会继续调用其自身。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值