cover_image

Spring源码系列:BeanDefinition载入(中)

glmapper 磊叔的技术博客 2018年02月04日 23:48
  • Web核心-Servlet

  • Spring源码系列:启动过程

  • Spring源码系列:容器刷新

  • Spring源码系列:BeanFactory的创建

  • Spring源码系列:BeanDefinition源码解析

  • Spring源码系列:BeanDefinition载入(上)

  • Spring源码系列:BeanDefinition载入(中)

  • Spring源码系列:BeanDefinition载入(下)

上一篇是将Bean的解析注册流程进行了梳理,对于一些细节问题没有进行细究,比如说元素属性值的处理,构造函数的处理等等。本篇就学习记录一下相关点。

首先来看下是在哪个地方具体生成BeanDefinitiond的。下面是方法请求的顺序。

  • 1. DefaultBeanDefinitionDocumentReader.parseDefaultElement

  • 2. DefaultBeanDefinitionDocumentReader.processBeanDefinition

  • 3. BeanDefinitionParserDelegate.parseBeanDefinitionElement

关于元素的解析绝大多数都是在BeanDefinitionParserDelegate及其子类中完成的。OK,来看下parseBeanDefinitionElement这个方法:

public AbstractBeanDefinition parseBeanDefinitionElement(
       Element ele, String beanName, BeanDefinition containingBean)
{

   this.parseState.push(new BeanEntry(beanName));
   String className = null;
   //在这里是读取<bean>的class名字,然后载入到BeanDefinition中,并未做实例化
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
       className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }

   try {
       String parent = null;
       if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
           parent = ele.getAttribute(PARENT_ATTRIBUTE);
       }
       //生成BeanDefinition对象
       AbstractBeanDefinition bd = createBeanDefinition(className, parent);
       //解析当前bean的属性
       parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
       //设置description信息
       bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
       //对bean的元素信息进行解析
       parseMetaElements(ele, bd);
       parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
       parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
       //解析bean的构造函数设置
       parseConstructorArgElements(ele, bd);
       //解析property设置
       parsePropertyElements(ele, bd);
       parseQualifierElements(ele, bd);

       bd.setResource(this.readerContext.getResource());
       bd.setSource(extractSource(ele));

       return bd;
   }
   //异常1:ClassNotFoundException
   catch (ClassNotFoundException ex) {
       error("Bean class [" + className + "] not found", ele, ex);
   }
   //异常2:NoClassDefFoundError
   catch (NoClassDefFoundError err) {
       error("Class that bean class [" + className + "] depends on not found", ele, err);
   }
   //其他未知错误
   catch (Throwable ex) {
       error("Unexpected failure during bean definition parsing", ele, ex);
   }
   finally {
       this.parseState.pop();
   }

   return null;
}

此处我们以解析property为例,看下具体的处理细节:

//解析给定bean元素的属性子元素。
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
   //获取子元素节点
   NodeList nl = beanEle.getChildNodes();
   //遍历
   for (int i = 0; i < nl.getLength(); i++) {
       Node node = nl.item(i);
       //是否包含property标识
       if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
           parsePropertyElement((Element) node, bd);
       }
   }
}

接着是执行具体property,在parsePropertyElement中完成:

//解析一个property元素。
public void parsePropertyElement(Element ele, BeanDefinition bd) {  
   //首先获取到property的名称
   String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
   //检查是否有name
   if (!StringUtils.hasLength(propertyName)) {
       error("Tag 'property' must have a 'name' attribute", ele);
       return;
   }
   this.parseState.push(new PropertyEntry(propertyName));
   try {
      //验证在同一个bean中存在同名的property,存在的话就不解析了,直接返回
       if (bd.getPropertyValues().contains(propertyName)) {
           error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
           return;
       }
       //解析出property的值
       Object val = parsePropertyValue(ele, bd, propertyName);
       //封装成PropertyValue对象
       PropertyValue pv = new PropertyValue(propertyName, val);
       parseMetaElements(ele, pv);
       pv.setSource(extractSource(ele));
       bd.getPropertyValues().addPropertyValue(pv);
   }
   finally {
       this.parseState.pop();
   }
}

在parsePropertyValue中,是对所有的property子元素进行具体解析的。我们知道property中除了单值之外,还会包括如:list,set,map,prop等集合元素;这些都会被封装成对应的Managerd对象。比如:ManagedList等。不同的集合类型页同样对应一种解析方法,比如解析list的是使用parseListElement。这些解析都是在BeanDefinitionParserDelegate类中完成的。这个后面我会抽一篇来学习BeanDefinitionParserDelegate这个类。

Bean的载入过程就是这样通过层层解析来完成的,但是对于目前的Ioc容器来说,仅仅是完成了对Bean对象管理的一些数据准备工作,也就是初始化工作,目前的BeanDefginiton中包含的就是一些静态的配置信息,Bean的实例化还没有进行,这个实例化的过程是在依赖注入时候完成的。


微信扫一扫
关注该公众号

继续滑动看下一个
磊叔的技术博客
向上滑动看下一个