注册 Bean Definitions流程

Spring Beans的初始化流程

ClassPathXmlApplicationContext初始化beand的流程在这里插入图片描述
Spring 容器对 Singleton bean 从初始化并注册到当前容器的与之相关的主要有两个流程,
1.解析 bean definitions 并注册

2.从1 中找到所有的已注册的 singleton bean definitions,遍历,实例化得到 Singleton beans

bean definitions

bean definitions就是用来描述 bean 配置中的 element 元素的
例如

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
   
   <context:component-scan base-package="org.shangyang" />  
   
   <bean name="jane" class="org.shangyang.spring.container.Person">
       <property name="name" value="Jane Doe"/>
   </bean>
   
</beans>

可以看到,上面有三个 element

1., root element
2.context:component/, component-scan element
3., bean element
在配置文件 beans.xml 被 Spring 解析的过程中,每一个 element 将会被解析为一个 bean definition 对象缓存在 Spring 容器中;
➥ 需要被描述为 bean definitions 的配置对象主要分为如下几大类,

  1. xml-based,解析 xml beans 的情况;
  2. 使用 @Autowired、@Required 注解注入 beans 的解析情况;
    需要特殊处理并解析的元素 context:annotation-config/
  3. 使用 @Component、@Service、@Repository,@Beans 注解注入 beans 的解析情况;需要特殊处理并解析的元素 context:annotation-scan/

一、首选初始化得到 BeanFactory 实例 DefaultListableBeanFactory,用来注册解析配置后生成的 bean definitions;
二、然后通过 XmlBeanDefinitionReader 解析 Spring XML 配置文件
根据用户指定的 XML 文件路径 location,进行解析并且得到 Resource[] 对象,具体参考 step 1.1.3.3.1.1 getResource(location) 步骤;这里,对其如何通过 location 得到 Resource[] 对象做进一步分析

public Resource[] getResources(String locationPattern) throws IOException {
   Assert.notNull(locationPattern, "Location pattern must not be null");
   if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
      // a class path resource (multiple resources for same name possible)
      if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
         // a class path resource pattern
         return findPathMatchingResources(locationPattern);
      }
      else {
         // all class path resources with the given name
         return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
      }
   }
   else {
      // Only look for a pattern after a prefix here
      // (to not get fooled by a pattern symbol in a strange prefix).
      int prefixEnd = locationPattern.indexOf(":") + 1;
      if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
         // a file pattern
         return findPathMatchingResources(locationPattern);
      }
      else {
         // a single resource with the given name
         return new Resource[] {getResourceLoader().getResource(locationPattern)};
      }
   }
}

三、从2 解析得到的 Resource 实例 resource 对应的是 beans.xml 的配置信息,从 step 1.1.3.3.1.2 loadBeanDefinitions 开始将会对 resource 既是 beans.xml 中的元素依次进行解析;首先生成对应 beans.xml 的 org.w3c.Document 对象实例 document,见 step 1.1.3.3.1.2.2.1,其次得到解析 document 对象的 BeanDefinitionDocumentReader 实例 documentReader,将当前的 Resource 对象封装为 XmlReaderContext 实例 xmlReaderContext,最后通过 documentReader 开始正式解析 document 对象得到 bean definitions 并将其注册到当前的 beanFactory 实例中

当完成上述三个步骤以后,将进入 register bean definitions process 流程

1.从 document 对象中获得了 Root 实例 root

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

首先,判断 root 元素的 namespace 对应的是不是 default namespace,若不是,将进入 parse custom element
遍历 root 元素下的所有 element,

若 element 的 namespace 是 default namespace,将进入 parse default element 流程;
比如当前 element 是普通的
若 element 的 namespace 不是 default namespace,将进入 parse custom element 流程;
比如当前 element 是 context:annotation-config/ 或者是 context:component-scan/

parse default element process

在这里插入图片描述
解析 bean element 流程
➥ 首先,通过 BeanDefintionParserDelegate 对象解析该 element,得到一个 BeanDefinitionHolder 对象 bdHolder 实例;该解析过程中会依次去解析 bean id, bean name, 以及相关的 scope, init, autowired model 等等属性;

➥ 其次,对 bean definition 进行相关的修饰操作

常规步骤

1.遍历当前 element 中的所有 attributes,依次得到 atttribute node
2.取得 node 所对应的 namespace URI,并判断该 namespace 是否是 custom namespace,如果是 custom namespace,那么正式进入对该 attribute node 的修饰过程,如下所述;
attribute node 的修饰过程

假设,我们当前的 attribute node 为 p:spouse-ref=”jane”,看看该属性是如何被解析的,

首先,通过 node namespace 得到对应的 NamespaceHandler 实例 handler
通过 xmlns:p=”http://www.springframework.org/schema/p" 得到的 NamespaceHandler 为 SimplePropertyNamespaceHandler 对象;

其次,调用 SimplePropertyNamespaceHandler 对象对当前的元素进行解析;
可以看到,前面的解析并没有什么特殊的,从元素 p:spouse-ref=”jane” 中解析得到 propery name: spouse-ref,property value: jane;但是后续解析,比较特殊,需要处理 REF_SUFFIX 的情况了,也就是当 property name 的后缀为 -ref 的情况,表示该 attribute 是一个 ref-bean 属性,其属性值引用的是其它的 bean 实例,所以呢,这里将其 property value 封装为了一个 RuntimeBeanReference 对象实例,表示将来在解析该 property value 为 Java Object 的时候,需要去初始化其引用的 bean 实例 jane,然后注入到当前的 property value 中;

最后,将解析后得到的 bean definition 封装在 bean definition holder 对象中进行返回;
➥ 最后,注册 bean definition;
参考
https://www.shangyang.me/2017/04/07/spring-core-container-sourcecode-analysis-register-bean-definitions/

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值