目录
代码块1:parseBeanDefinitionElement
代码块2:parseBeanDefinitionElement
代码块3:parseBeanDefinitionAttributes
代码块4:parseConstructorArgElements
代码块5:parseConstructorArgElement
Spring IoC源码学习全系列
Spring IoC源码学习:ApplicationContext刷新前的配置
Spring IoC源码学习:obtainFreshBeanFactory详解
Spring IoC源码学习:parseDefaultElement详解
Spring IoC源码学习:parseCustomElement详解
Spring IoC源码学习:context:component-scan节点详解
Spring IoC源码学习:invokeBeanFactoryPostProcessors详解
Spring IoC源码学习:registerBeanPostProcessors详解
Spring IoC源码学习:finishBeanFactoryInitialization详解
Spring IoC源码学习:createBean详解(上)
Spring IoC源码学习:createBean详解(下)
Spring IoC源码学习:finishRefresh 详解
接着Spring IoC:obtainFreshBeanFactory详解继续往下解析,本文来到 parseDefaultElement 方法。该方法是解析默认命名空间节点的方法,是加载 bean 定义模块的最核心方法。
首先让我们回到Spring IoC:obtainFreshBeanFactory详解文末的 parseBeanDefinitions 方法。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 1.默认命名空间的处理 if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); // 遍历root的子节点列表 for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // 1.1 默认命名空间节点的处理,例如: <bean id="test" class="" /> parseDefaultElement(ele, delegate); } else { // 1.2 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/> delegate.parseCustomElement(ele); } } } } else { // 2.自定义命名空间的处理 delegate.parseCustomElement(root); } }
1.1 默认命名空间节点的处理,见下面 parseDefaultElement 方法。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { // 1.对import标签的处理 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } // 2.对alias标签的处理 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } // 3.对bean标签的处理(最复杂最重要) else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } // 4.对beans标签的处理 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
可以看到默认命名空间的一级节点只有4种:import、alias、bean、beans。这4种节点中,最重要、最复杂的就是 <bean> 节点,本文只会介绍 <bean> 节点的处理,理解了<bean> 节点后,其他的都不难理解。另外,<beans> 节点只是递归调用之前的 doRegisterBeanDefinitions 方法,因此无需再介绍。
接下来,让我们从 processBeanDefinition(ele, delegate) 方法正式开始。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 1.进行节点定义解析, 经过这个方法后,bdHolder会包含一个Bean节点的所有属性,例如name、class、id BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 2.若存在默认标签的子节点下再有自定义属性,需要再次对自定义标签再进行解析(基本不用,不做深入解析) bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 3.解析节点定义完成后,需要对解析后的bdHolder进行注册 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. // 4.最后发出响应事件,通知相关的监听器,这个Bean已经加载完成了 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
1. 进行节点定义解析,见代码块1详解。
2. 例如下图这种,基本不用,不做深入解析。
3. 解析节点定义完成后,需要对解析后的 bdHolder 进行注册,见代码块13详解。
4. 发出响应事件,通知相关的监听器,不做深入解析。
代码块1:parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 1.解析name和id属性 // 解析id属性 String id = ele.getAttribute(ID_ATTRIBUTE); // 解析name属性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // 分割name属性(通过逗号或分号) // 例如:<bean name="demoService,demoServiceAlias" class=""/>,分割后aliases为[demoService, demoServiceAlias] List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } // beanName默认使用id String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { // 如果id为空,并且aliases不为空,则取aliases的第一个元素作为beanName,其他的仍作为别名 beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { // 检查beanName和aliases是否在同一个 <beans> 下已经存在 checkNameUniqueness(beanName, aliases, ele); } // 2.进一步解析bean的其他所有属性并统一封装至GenericBeanDefinition类型实例中 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { // 3.如果bean定义存在,但是beanName为空,则用Spring默认的生成规则为当前bean生成beanName if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { // Spring提供的生成规则生成beanName,例如:com.joonwhee.open.demo.service.impl.DemoServiceImpl#0 beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { // 如果Spring默认的生成规则生成的beanName为:类名加后缀,则将类名注册为别名 aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); // 4.将bean定义、beanName、bean别名数组封装成BeanDefinitionHolder return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
1.解析 name 和 id 属性,其中 name 属性可以通过分割符设置多个。如果 id 存在,则 使用 id 作为 beanName,name 属性分割后全部作为别名;如果 id 不存在,则将 name 属性分割后的第1个作为 beanName,剩下的全部作为别名。
举个例子:
1
<!-- 配置1 --> <bean id="appleService" name="appleOne;appleTwo" class="com.joonwhee.AppleServiceImpl"/> <!-- 配置2 --> <bean name="bananaOne;bananaTwo" class="com.joonwhee.BananaServiceImpl"/>
配置1:beanName=appleService,aliases=[appleOne, appleTwo] ;
配置2:beanName=bananaOne,aliases=[bananaTwo]
2.进一步解析 bean 的其他所有属性并统一封装至GenericBeanDefinition 类型实例中,见代码块2详解。
代码块2:parseBeanDefinitionElement
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; // 1.解析class、parent属性 // 解析class属性 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; // 解析parent属性 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } // 2.创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 3.解析bean的各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 提取description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // 解析元数据子节点(基本不用, 不深入介绍) parseMetaElements(ele, bd); // 解析lookup-method子节点(基本不用, 不深入介绍) parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // 解析replaced-method子节点(基本不用, 不深入介绍) parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 4.解析constructor-arg子节点 parseConstructorArgElements(ele, bd); // 5.解析property子节点 parsePropertyElements(ele, bd); // 解析qualifier子节点(基本不用, 不深入介绍) parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } 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; }
1.解析了class、parent属性,因为第2步创建AbstractBeanDefinition 需要用到这两个属性,否则,这两个属性可以放到第3步一起解析。
2.创建用于承载属性的 AbstractBeanDefinition 类型的GenericBeanDefinition。比较简单,直接 new 一个 GenericBeanDefinition,如果className 和 classLoader 不为空,则通过反射构建出 BeanClass,并设置为 GenericBeanDefinition 的属性。
3.解析 bean 的剩余属性,见代码块3详解。
4.解析 constructor-arg 子节点,见代码块4详解。
5.解析 property 子节点,见代码块11详解。
代码块3:parseBeanDefinitionAttributes
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { // 解析singleton属性 if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { // singleton属性已经不支持, 如果使用了会直接抛出异常, 请使用scope属性代替 error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } // 解析scope属性 else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. bd.setScope(containingBean.getScope()); } // 解析abstract属性 if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } // 解析lazy-init属性, 默认为false String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); // 解析autowire属性 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); // 解析dependency-check属性 String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); // 解析depends-on属性 if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } // 解析autowire-candidate属性 String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } // 解析primary属性 if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } // 解析init-method属性 if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); if (!"".equals(initMethodName)) { bd.setInitMethodName(initMethodName); } } else { if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } } // 解析destroy-method属性 if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); bd.setDestroyMethodName(destroyMethodName); } else { if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } } // 解析factory-method属性 if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } // 解析factory-bean属性 if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; }
内容比较简单,就是从节点 ele 拿到所有的属性值,塞给AbstractBeanDefinition 的对应属性。这些属性的使用如下图。
代码块4:parseConstructorArgElements
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { // 拿到beanEle节点的所有子节点 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { // 解析constructor-arg parseConstructorArgElement((Element) node, bd); } } }
拿到 beanEle 节点的所有子节点,遍历解析所有是 constructor-arg节点的子节点,见代码块5详解。
例子:
constructor-arg 的使用如下图所示,constructor-arg 节点类似于构造函数,bean 中必须要有相应的构造函数才可以使用,否则会报错。
代码块5:parseConstructorArgElement
public void parseConstructorArgElement(Element ele, BeanDefinition bd) { // 1.提取基础属性index、type、name属性值 // 提取index属性 String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); // 提取type属性 String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); // 提取name属性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(indexAttr)) { try { int index = Integer.parseInt(indexAttr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { // 2.index不为空的处理 this.parseState.push(new ConstructorArgumentEntry(index)); // 2.1解析ele节点对应的属性值 Object value = parsePropertyValue(ele, bd, null); // 2.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); // 2.3将type属性封装到ConstructorArgumentValues.ValueHolder if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } // 2.4将name属性封装到ConstructorArgumentValues.ValueHolder if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); // 2.5判断index是否重复指定, 如果是则抛出异常 if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } else { // 将index和valueHolder以key-value形式添加至当前BeanDefinition的constructorArgumentValues // 的indexedArgumentValues属性中,(用于上面判断index是否重复指定) bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { try { // 3.index为空的处理 this.parseState.push(new ConstructorArgumentEntry()); // 3.1解析ele节点对应的属性值 Object value = parsePropertyValue(ele, bd, null); // 3.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); // 3.3将type属性封装到ConstructorArgumentValues.ValueHolder if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } // 3.4将name属性封装到ConstructorArgumentValues.ValueHolder if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); // 3.5将valueHolder添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中 // 与上面的indexedArgumentValues类似,上面有index存为map,这边没index存为list bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } }
1.首先拿到基础属性 index、type、name 的属性值。
2.index不为空的处理:
2.1 首先解析 ele 节点的值,可以看代码块4里的图,每个 constructor-arg 节点必然有一个属性值,可能是通过 value 属性、ref 属性、list 属性等。见代码块6详解。
2.5 判断index是否重复指定,如果是则抛出异常;如果不重复,则将 index 和 valueHolder 以 key-value 形式添加至当前BeanDefinition 的constructorArgumentValues 的indexedArgumentValues 属性中(用于前面判断index是否重复指定)。
3.index为空的处理。基本与2相同,不在赘述。
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. // 1.拿到ele节点的子节点,例如list、map NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); // 跳过description或者meta节点 if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { // 只能有1个子节点,否则抛出异常 error(elementName + " must not contain more than one sub-element", ele); } else { // 找到子节点,赋值给subElement subElement = (Element) node; } } } // 2.解析constructor-arg上的ref属性 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); // 3.解析constructor-arg上的value属性 boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); // 4.合法性校验。在constructor-arg上:ref属性、value属性、子节点,三者只能有1个,因为这三个都是用来表示该节点的值。 if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { // 5.ref属性的处理,使用RuntimeBeanReference封装对应的ref值(该ref值指向另一个bean的beanName), // RuntimeBeanReference起到占位符的作用,ref指向的beanName将在运行时被解析成真正的bean实例引用 String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { // 6.value属性的处理,使用TypedStringValue封装 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { // 7.解析子节点 return parsePropertySubElement(subElement, bd); } else { // 8.既没有ref属性,也没有value属性,也没有子节点,没法获取ele节点的值,直接抛异常 // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } }
1.拿到 ele 节点的子节点,并赋值给变量 subElement。例如下图中 index="3" 的节点就有子节点,子节点为 list,其他 4 个都没有子节点。
7.解析子节点,见代码块7详解。
public Object parsePropertySubElement(Element ele, BeanDefinition bd) { return parsePropertySubElement(ele, bd, null); } public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { // 1.校验是否为默认的命名空间,如果不是则走解析自定义节点代码 if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } // 2.解析bean节点 else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } // 3.解析ref节点 else if (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } // 4.解析idref节点 else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } // 5.解析value节点 else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } // 6.解析null节点 else if (nodeNameEquals(ele, NULL_ELEMENT)) { // It's a distinguished null value. Let's wrap it in a TypedStringValue // object in order to preserve the source location. TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } // 7.解析array节点 else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } // 8.解析list节点 else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } // 9.解析set节点 else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } // 10.解析map节点 else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } // 11.解析props节点 else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { // 12.未知属性,抛异常 error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
1.解析自定义命名空间节点。之后会介绍该内容,本处暂不介绍。
2.解析 bean 节点,之前已经走过该方法,见代码块1详解。
5.解析 value 节点,见代码块8详解。
8.解析 list 节点,7 到 11 的解析都比较类似,这边拿常用的 list 来介绍。见代码块10详解。
public Object parseValueElement(Element ele, String defaultTypeName) { // It's a literal value. // 拿到ele节点值 String value = DomUtils.getTextValue(ele); // 拿到ele节点的type属性 String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE); String typeName = specifiedTypeName; if (!StringUtils.hasText(typeName)) { // ele节点没有type属性则则使用入参defaultTypeName typeName = defaultTypeName; } try { // 1.使用value和type构建TypedStringValue TypedStringValue typedValue = buildTypedStringValue(value, typeName); typedValue.setSource(extractSource(ele)); typedValue.setSpecifiedTypeName(specifiedTypeName); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + typeName + "] not found for <value> element", ele, ex); return value; } }
1.使用 value 和 typeName 构建 TypedStringValue,见代码块9详解。
protected TypedStringValue buildTypedStringValue(String value, String targetTypeName) throws ClassNotFoundException { ClassLoader classLoader = this.readerContext.getBeanClassLoader(); TypedStringValue typedValue; // 1.targetTypeName为空,则只使用value来构建TypedStringValue if (!StringUtils.hasText(targetTypeName)) { typedValue = new TypedStringValue(value); } // 2.targetTypeName不为空,并且classLoader不为null else if (classLoader != null) { // 2.1 利用反射,构建出type的Class,如果type是基本类型,或者 java.lang 包下的常用类, // 可以直接从缓存(primitiveTypeNameMap、commonClassCache)中获取 Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader); typedValue = new TypedStringValue(value, targetType); } else { typedValue = new TypedStringValue(value, targetTypeName); } return typedValue; }
public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) { // 1.拿到collectionEle节点的value-type,顾名思义,该属性就是该list节点下的value的类型 String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); // 2.拿到collectionEle节点的所有子节点, 一般为<value> NodeList nl = collectionEle.getChildNodes(); // 3.new一个ManagedList,用于存放字节点的值 ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); // 4.解析子节点集合 parseCollectionElements(nl, target, bd, defaultElementType); return target; } protected void parseCollectionElements( NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) { // 4.1 遍历elementNodes for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); // 4.2 跳过description节点 if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) { // 4.3 调用parsePropertySubElement方法对节点进行解析, 正常list的子节点为<value>节点会直接走到value节点的解析 // 如果list的子节点还是list,则相当于递归在走到此方法 target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } }
4.3 调用 parsePropertySubElement 方法对节点进行解析,见代码块7详解。
正常情况下,list 里面应该是 value节点(见下图),则会走到代码块8解析出对应的value,然后结束。特殊情况下,可能 list 里面还是 list,则相当于递归在走到此方法。
至此,代码块4 ~ 代码块10 完成了constructor-arg节点的解析,让我们回到代码块2的第5点,继续解析 property 子节点。
public void parsePropertyElements(Element beanEle, BeanDefinition bd) { // 拿到beanEle节点的所有子节点 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { // 解析property节点 parsePropertyElement((Element) node, bd); } } }
拿到 beanEle 节点的所有子节点,遍历解析所有是 property 节点的子节点,见代码块12详解。
property 的使用如下图所示,property 节点类似于set方法,bean 中的属性必须要有 set 方法才可以使用,否则会报错。
public void parsePropertyElement(Element ele, BeanDefinition bd) { // 1.拿到name属性 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { // name属性为必要属性,如果没有配置,则抛出异常 error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { // 2.校验在相同bean节点下,是否存在相同的name属性,如果存在则抛出异常 if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } // 3.解析属性值 Object val = parsePropertyValue(ele, bd, propertyName); // 4.将解析的属性值和属性name封装成PropertyValue PropertyValue pv = new PropertyValue(propertyName, val); // 5.解析meta节点(基本不用,不深入解析) parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); // 6.将解析出来的PropertyValue,添加到BeanDefinition的propertyValues属性中(上面的重复校验用到) bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }
3.解析属性值,上文已经介绍过该方法,见代码块6详解。
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. // 1.拿到beanName String beanName = definitionHolder.getBeanName(); // 2.注册beanName、BeanDefinition到缓存中(核心逻辑),实现类为; DefaultListableBeanFactory registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. // 注册bean名称的别名(如果有的话) String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { // 3.注册bean的beanName和对应的别名映射到缓存中(缓存:aliasMap) registry.registerAlias(beanName, alias); } } }
2.注册 beanName、BeanDefinition 到缓存中,见代码块14详解。
3.如果有别名,则注册 bean 的 beanName 和对应的别名映射到 aliasMap 缓存中,见代码块16详解。
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // 1.beanName和beanDefinition为空校验 Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { // 注册前的最后校验 ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; // 首先根据beanName从beanDefinitionMap缓存中尝试获取 oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { // 2.beanName存在于缓存中 if (!isAllowBeanDefinitionOverriding()) { // 如果不允许相同beanName重新注册,则直接抛出异常 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存(以供后续创建bean时使用) this.beanDefinitionMap.put(beanName, beanDefinition); } else { // 3.beanName不存在于缓存中 if (hasBeanCreationStarted()) { // 3.1 bean创建阶段已经开始 // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存 this.beanDefinitionMap.put(beanName, beanDefinition); // 将本次传进来的beanName 加入beanDefinitionNames缓存 List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 将beanName从manualSingletonNames缓存移除 if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // 3.2 bean创建阶段还未开始 // Still in startup registration phase // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存 this.beanDefinitionMap.put(beanName, beanDefinition); // 将本次传进来的beanName 加入beanDefinitionNames缓存 this.beanDefinitionNames.add(beanName); // 将beanName从manualSingletonNames缓存移除 this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } // 4.如果存在相同beanName的BeanDefinition,并且beanName已经存在单例对象,则将该beanName对应的缓存信息、单例对象清除, // 因为这些对象都是通过oldBeanDefinition创建出来的,需要被覆盖掉的, // 我们需要用新的BeanDefinition(也就是本次传进来的beanDefinition)来创建这些缓存和单例对象 if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
这个方法会将 beanName 添加到beanDefinitionNames 缓存,将 beanName 和 BeanDefinition 的映射关系添加到beanDefinitionMap 缓存。
如果 beanName不重复(一般不会重复),对于我们当前正在解析的 obtainFreshBeanFactory 方法来说,因为 bean 创建还未开始,因此会走到 3.2 进行缓存的注册。
4.如果 beanName 重复,并且该 beanName 已经存在单例对象,则会调用 resetBeanDefinition 方法,见代码块15详解。
protected void resetBeanDefinition(String beanName) { // Remove the merged bean definition for the given bean, if already created. // 1.删除beanName的mergedBeanDefinitions缓存(如果有的话) clearMergedBeanDefinition(beanName); // Remove corresponding bean from singleton cache, if any. Shouldn't usually // be necessary, rather just meant for overriding a context's default beans // (e.g. the default StaticMessageSource in a StaticApplicationContext). // 2.从单例缓存中删除该beanName对应的bean(如果有的话) destroySingleton(beanName); // Reset all bean definitions that have the given bean as parent (recursively). // 3.重置beanName的所有子Bean定义(递归) for (String bdName : this.beanDefinitionNames) { if (!beanName.equals(bdName)) { BeanDefinition bd = this.beanDefinitionMap.get(bdName); // 当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置 if (beanName.equals(bd.getParentName())) { resetBeanDefinition(bdName); } } } }
比较简单,将该 beanName 的mergedBeanDefinitions 缓存信息删除、单例缓存删除。如果存在子 bean 定义,则递归重置。实际开发过程中,基本不会出现 beanName 相同的情况,因此基本不会走到该方法。
@Override public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); // 1.如果别名和beanName相同,则不算别名,从aliasMap缓存中移除 if (alias.equals(name)) { this.aliasMap.remove(alias); } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register // 2.如果别名已经注册过,直接返回 return; } // 3.如果存在相同的别名,并且不允许别名覆盖,则抛出异常 if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } } // 4.检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A checkForAliasCircle(name, alias); // 5.将别名和beanName的映射放到aliasMap缓存中 this.aliasMap.put(alias, name); } }
将别名和 beanName 注册到 aliasMap 缓存。
我们可以重新梳理一下思路,我们首先将 xml 中的 bean 配置信息进行了解析,并构建了AbstractBeanDefinition(GenericBeanDefinition)对象来存放所有解析出来的属性。
然后,我们将 AbstractBeanDefinition 、beanName、aliasesArray 构建成BeanDefinitionHolder 对象并返回。
最后,我们通过 BeanDefinitionHolder 将 BeanDefinition 和 beanName 注册到 BeanFactory 中,也就是存放到缓存中。
执行完 parseDefaultElement 方法,我们得到了两个重要的缓存:
· beanDefinitionNames 缓存。
· beanDefinitionMap 缓存。
这两个缓存在之后的 IoC 构建过程中会发挥很重要的作用,大家在这边先有个印象。