上一篇是将Bean的解析注册流程进行了梳理,对于一些细节问题没有进行细究,比如说元素属性值的处理,构造函数的处理等等。本篇就学习记录一下相关点。
首先来看下是在哪个地方具体生成BeanDefinitiond的。下面是方法请求的顺序。
关于元素的解析绝大多数都是在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的实例化还没有进行,这个实例化的过程是在依赖注入时候完成的。