spring源码---IOC:注册bean(xml方式)

接着上一节,讲到parseBeanDefinitions()方法,位于DefaultBeanDefinitionDocumentReader类中

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes(); //获取文档对象 所有子节点
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {  //xml元素节点
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) { //元素节点使用的是 spring默认的xml命名空间
               parseDefaultElement(ele, delegate); //【入】,解析该节点
            }
            else { //如果不是spring默认的xml命名空间,则使用用户自定义的解析规则解析元素节点
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

它对xml的第一层子节点,进行了遍历,并且解析,parseDefaultElement()方法

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { //<import>导入元素
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { //<alias>别名元素
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {//<bean>节点
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

由于代码量太多,我们重点关注 <bean>节点的解析,processBeanDefinition()方法

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   //...Holder是对 BeanDefinition的封装,即Bean定义的封装类
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //具体的节点解析 又delegate完成
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance. 向spring IOC容器注册解析到的 bean定义,这是bean定义向IOC容器注册的入口
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      // Send registration event. 完成向spring IOC容器注册解析得到的Bean定义之后,发送注册事件
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

 该代码,就是bean从xml到spring的最为【核心】的代码,首先该方法是xml解析的入口,具体的解析交给了delegate对象进行解析,而且解析内容很多,所以这里也不阐述了,我们重点关注如何向spring ioc容器注册。

    对于BeanDefinitionHolder上面注释中写到了,是对BeanDefinition的封装,代码内容很多。

BeanDefinitinoReaderUtils类中的registerBeanDefinition()方法

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {
   //获得BeanDefinitino的名字
   String beanName = definitionHolder.getBeanName();
   //【入】
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    //获取别名
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias); 
//注册别名,别名的存在也很有意思,在后期依赖注入getBean()有很大作用
      }
   }
}

    同样该方法是一个入口方法,主要处理了别名,它的具体注册交给了DefaultListableBeanFactory类

该类的继承关系图:

此类图很重要,我们要做到熟悉,在第二章DI中,我们会着重研究该类图,目前我们需要知道BeanDefinitino保存在了BeanFactory类的底层:DefaultListableBeanFactory类

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
...
   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   if (existingDefinition != null) { //已经存在
     ...
      this.beanDefinitionMap.put(beanName, beanDefinition); //【放入】
   }
   else {
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);  //【放入】
    //更新名字,直接扩容,然后全部添加,可能这样效率不高
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

 注意,全部放在了本类的beanDefinitionMap集合中!,bean就成功注册到了spring ioc容器中,可以通过bean的名字,获得beanDefintion对象,获得Bean的信息。

    注册完毕,回到DefaultBeanDefinitionDocumentReader的processBeanDefinitino()方法,它在注册完bean之后,需要发送注册事件。也就是调用fireComponentRegistered()方法

 

    最后,回到refresh()方法中,第二步:refreshBeanFactory()核心内容完成,现在更新beanFactory字段信息。beanFactory保存在第二层中,在refresh()方法(它存在于第一层AbstractApplicationContext类中),它getBeanFactory()方法,保存在局部变量中,余下的3,4,5,6,11等步骤调用的方法,都是使用beanFactory作为参数传入。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值