文章目录
Spring源码系列:
前言
正文
方法1:processBeanDefinition
方法2:parseBeanDefinitionElement
方法3:parseBeanDefinitionElement
方法4:parseBeanDefinitionAttributes
方法5:parseConstructorArgElements
方法6:parseConstructorArgElement
方法7:parsePropertyValue
方法8:parsePropertySubElement
方法9:parsePropertyElements
方法10:registerBeanDefinition
方法11:registerBeanDefinition
方法12:resetBeanDefinition
方法13:resetBeanDefinition
总结
Spring源码系列:
Spring IOC源码:简单易懂的Spring IOC 思路介绍
Spring IOC源码:核心流程介绍
Spring IOC源码:ApplicationContext刷新前准备工作
Spring IOC源码:obtainFreshBeanFactory 详解(上)
Spring IOC源码:obtainFreshBeanFactory 详解(中)
Spring IOC源码:obtainFreshBeanFactory 详解(下)
Spring IOC源码:<context:component-scan>源码详解
Spring IOC源码:invokeBeanFactoryPostProcessors 后置处理器详解
Spring IOC源码:registerBeanPostProcessors 详解
Spring IOC源码:实例化前的准备工作
Spring IOC源码:finishBeanFactoryInitialization详解
Spring IoC源码:getBean 详解
Spring IoC源码:createBean( 上)
Spring IoC源码:createBean( 中)
Spring IoC源码:createBean( 下)
Spring IoC源码:finishRefresh 完成刷新详解
前言
上篇文章我们介绍了prepareRefresh方法,配置解析前的准备工作,和obtainFreshBeanFactory方法,配置解析核心处理方法。我们讲解到了parseBeanDefinitions方法,该方法会根据命名空间去选择对应的逻辑处理。本章节介绍默认命名空间的处理逻辑parseDefaultElement(ele, delegate);
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) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { //默认命名空间节点的处理,例如: <bean id="test" class="" /> parseDefaultElement(ele, delegate); } else { // 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/> delegate.parseCustomElement(ele); } } } } else { //非默认命名空间走其它逻辑 delegate.parseCustomElement(root); } }
正文
进入parseDefaultElement(ele, delegate)方法,我们可以看到有四种类型的判断,import、alias、bean、beans。这里获取一级节点,判断节点类型选择对应的解析方法。几种类型的解析都是比较类似的,这里我们使用的bean,学会的bean去看其它都是大同小异,而beans节点其实是重新调用一遍doRegisterBeanDefinitions方法,进行子节点的遍历解析工作。bean节点解析见方法1
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //解析import if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //解析alias else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //解析bean else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //解析beans else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="teacher" class="service.impl.Teacher"> <property name="name" value="张三"></property> <property name="age" value="30"></property> </bean> </beans>
方法1:processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //通过解析器进行解析,解析出类名、class、id、父类、属性依赖等 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //bean解析器只能解析一些默认的配置,这里判断是否有自定义的属性或子节点需要进一步解析并封装, bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 将bdHolder 注册到上下文缓存中beanDefinitionNames、beanDefinitionMap、aliasMap BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
1、delegate.parseBeanDefinitionElement(ele)方法:见方法2详解
2、delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)方法:
这个方法主要是考虑到bean节点中的属性或者子节点包含了自定义内容,默认的解析器没办法解析到,所以需要做下后置处理,判断是否有自定义的,通过自定义获取命名空间,通过命名空间加载解析器进行处理,将处理好的值封装到步骤1解析出来的BeanDefinitionHolder 中。例如下面的“zhudachang”属性和 < myBean > 子节点。这节我们要研究默认命名空间,所以这里不做深入,等后面讲解了自定义的内容后,再来看这块就比较简单了。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="teacher" class="service.impl.Teacher" zhudachang=""> <property name="name" value="张三"></property> <property name="age" value="30"></property> <myBean></myBean> </bean> </beans>
方法2:parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { //获取id和name属性值 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); //对name属性值匹配“,;”切割看是否有多个名称,加入别名缓存 List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } //如果beanName为空,则以aliases中的第一条数据作为beanName名称,并移除。 String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isTraceEnabled()) { logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } //查询一下该beanName 名称是否作为第一个被使用了 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } //解析节点并封装成GenericBeanDefinition AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { //默认规则生成,获取class名称,如果class名称为空,则看beanDefinition的父类或FactoryBean的名称+固定后最作为Bean名称,如果是内部的Bean则按另一个逻辑生成; beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { 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)) { aliases.add(beanClassName); } } if (logger.isTraceEnabled()) { logger.trace("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); //将beanDefinition跟类名、别名封装成 BeanDefinitionHolder return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
1、beanName的获取规则,如果bean节点配置了id属性,则以id作为beanName。如果没有id,但是有配置name属性,则解析名称中是否含有多个,如果有多个则将第一个作为beanName,其余的作为别名,加入aliases集合中。
例如:
<bean name="ZHU,DA,CHANG" class="service.impl.Teacher"> <property name="name" value="张三"></property> <property name="age" value="30"></property> </bean>
这里的beanName为"ZHU",别名为“DA”,“CHANG"
<bean id="teacher" name="zhudachang" class="service.impl.Teacher"> <property name="name" value="张三"></property> <property name="age" value="30"></property> </bean>
这里的beanName为"teacher",别名为“zhudachang”
2、parseBeanDefinitionElement(ele, beanName, containingBean)方法:见方法3详解
方法3:parseBeanDefinitionElement
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { //将beanName封装成BeanEntry对象 this.parseState.push(new BeanEntry(beanName)); //获取class类属性 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } //获取父类属性 String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { //创建GenericBeanDefinition,并设置父类名称,通过className获取class并设置 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //解析设置各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); //设置description信息 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //解析元数据 parseMetaElements(ele, bd); //设置LookupOverride parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //设置ReplacedMethod parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析设置构造函数节点 parseConstructorArgElements(ele, bd); //解析设置子节点属性 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、parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)方法,见方法4详解
2、parseLookupOverrideSubElements(ele, bd.getMethodOverrides())
该方法主要解析子节点中的< lookup-method >标签,该标签处理Bean中属性为原型模式,也就是每次获取该属性时都会新创建一个对象。
如:Teacher类中声明了Address属性,而我们的Address是prototype原型模式,也就是每次获取该值都会创建一个新的对象,而Teacher是一个单例,获取该类时,每次都从缓存中获取,导致类中的Adress也是一个单例,这里就是为后续处理该问题作准备。后续文章会专门讲解这个的用法。
<bean name="address" class="service.Address" scope="prototype"></bean> <bean id="teacher" name="teacher" class="service.impl.Teacher" > <lookup-method name="getAddress" bean="address"></lookup-method> </bean>
3、parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
<bean name="address" class="service.Address" scope="prototype"></bean> <bean id="teacher" name="teacher" class="service.impl.Teacher" > <replaced-method name="getAddress" replacer="addressMethodReplacer"></replaced-method> </bean>
4、parseConstructorArgElements(ele, bd)方法,见方法5详解
5、parsePropertyElements(ele, bd)方法见方法9详解
方法4:parseBeanDefinitionAttributes
// 解析设置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; }
方法5:parseConstructorArgElements
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)) { parseConstructorArgElement((Element) node, bd); } }
这里遍历子节点中的< constructor-arg >标签,对其属性进行解析封装,parseConstructorArgElement((Element) node, bd)方法见方法6详解
<bean id="address" class="service.Address" ></bean> <bean id="teacher" name="teacher" class="service.impl.Teacher"> <constructor-arg index="0" value="zhangsan"></constructor-arg> <constructor-arg index="1" value="13"></constructor-arg> <constructor-arg index="2" ref="address"></constructor-arg> <constructor-arg index="3" > <list> <value>zhudachang1</value> <value>zhudachang2</value> <value>zhudachang3</value> </list> </constructor-arg> </bean>
方法6:parseConstructorArgElement
public void parseConstructorArgElement(Element ele, BeanDefinition bd) { //获取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)) { //如果有index属性 try { int index = Integer.parseInt(indexAttr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { //校验该index是否>=0,否则抛异常 this.parseState.push(new ConstructorArgumentEntry(index)); //获取其值,可能是通过 value 属性、ref 属性、list 属性等 Object value = parsePropertyValue(ele, bd, null); //封装成ConstructorArgumentValues对象 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { //设置type值 valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { //设置name值 valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } else { //添加下标及其对应的值 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 { //如果没有index,此时不做校验 this.parseState.push(new ConstructorArgumentEntry()); //获取当前设置值,可能是通过 value 属性、ref 属性、list 属性等 Object value = parsePropertyValue(ele, bd, null); //同上面步骤一样 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); //由于没有下标,这里直接添加集合中 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } }
parsePropertyValue(ele, bd, null)方法,会解析出当前节点对应的引用类型值,见方法7详解
方法7:parsePropertyValue
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) { String elementName = (propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"); //获取该节点下的子节点 NodeList nl = ele.getChildNodes(); Element subElement = null; //如果是List类型,则有子节点。这里会对子节点进行校验 for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } //判断是否有该属性 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); //这里不允许有value跟ref共存或者跟有子节点的共存 如list 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) { //获取属性值并将该属性值封装成RuntimeBeanReference 对象 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) { //如果有value值,则封装成TypedStringValue TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { //如果有子节点,对子节点内容进行解析 return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } }
方法8:parsePropertySubElement
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) { //判断节点标签是否是默认命名空间,不是则走自定义逻辑 if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { //如果是Bean标签,则进行解析,并封装成BeanDefinitionHolder BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { //判断该节点是否有自定义标签,有则调用自定义逻辑处理,补充新的解析内容进来 nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // 如果是ref,引用其它Bean,获取引用的beanName名称 String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // 获取父类beanName refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean' 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 RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } //解析idref节点 else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } //解析value else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } //解析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; } //解析Array数组 else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } //解析List集合 else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } //解析Set集合 else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } //解析Map集合 else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } //解析props else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
1、list节点的解析,获取该节点下的子节点,遍历调用parsePropertySubElement,并将每个子节点添加至Collection中。
2、其它集合Map、Set、Array等的解析过程也跟list类似。
方法9:parsePropertyElements
以上我们介绍了< constructor-arg >标签的解析过程,下面来看下
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); } } }
public void parsePropertyElement(Element ele, BeanDefinition bd) { //获取name属性值 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } //校验该值不为空 this.parseState.push(new PropertyEntry(propertyName)); try { if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } //解析获取其值,该方法在前面的解析中有讲解过,这里不做讲解 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(); } }
xml配置案例如下:
<bean id="address" class="service.Address" scope="prototype"></bean> <bean id="teacher" class="service.impl.Teacher"> <property name="name" value="zhudachang"></property> <property name="age" value="11"></property> <property name="address" ref="address"></property> </bean>
到这里我们的解析工作就完成了,下面回到方法1中,解析后需要将BeanDefinition注册到上下文缓存中,见方法10详解
方法10:registerBeanDefinition
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // 获取beanName名称 String beanName = definitionHolder.getBeanName(); //注册到缓存中 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); //获取别名集合,注册到上下文的别名缓存中 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
1、我们看到传进来的是BeanDefinitionRegistry 注册器,我们可以把它当成管理上下文的工具类吧,使用它可以操作上下文的部分增删改查工作
2、registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())方法,见方法11详解
3、registry.registerAlias(beanName, alias)方法,见方法13详解
方法11:registerBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { //做下校验 Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); //如果是AbstractBeanDefinition,则校验 if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } //判断缓存中是否存在了该beanName的BeanDefinition BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } //加入缓存中,进行覆盖 this.beanDefinitionMap.put(beanName, beanDefinition); } else { //检查下当前bean工厂是否开始创建工作,这里是为了加锁 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { //将当前beanDefinition放入缓存中 this.beanDefinitionMap.put(beanName, beanDefinition); //统计下数量 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { // 将当前beanDefinition放入缓存中 this.beanDefinitionMap.put(beanName, beanDefinition); //将beanName加入缓存中 this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } //如果Bean存在于缓存中,并且的单例的,这里需要重置 if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
1、((AbstractBeanDefinition) beanDefinition).validate();
该方法用于校验节点中不能同时存在factory-method属性和子节点< lookup-method >、< replaced-method >。这个if语句是为了确保,上述两者不能共存,否则就会报错。这是因为,如果给一个 Bean 配置了工厂方法,那么它会由工厂方法来创建,而不是 Spring 默认的方式创建,这种情况下无法进行方法的覆盖。因此,这里的判断是为了确保配置信息没有出现冲突。
public void validate() throws BeanDefinitionValidationException { if (hasMethodOverrides() && getFactoryMethodName() != null) { throw new BeanDefinitionValidationException( "Cannot combine factory method with container-generated method overrides: " + "the factory method must create the concrete bean instance."); } if (hasBeanClass()) { prepareMethodOverrides(); } }
2、resetBeanDefinition(beanName)方法,见方法12详解
方法12:resetBeanDefinition
protected void resetBeanDefinition(String beanName) { // 从合并的MergedBeanDefinition缓存中移除 clearMergedBeanDefinition(beanName); //这里移除了很多处缓存,如IOC三级缓存等 destroySingleton(beanName); // 通知后置处理器进行重置处理 for (BeanPostProcessor processor : getBeanPostProcessors()) { if (processor instanceof MergedBeanDefinitionPostProcessor) { ((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName); } } for (String bdName : this.beanDefinitionNames) { if (!beanName.equals(bdName)) { BeanDefinition bd = this.beanDefinitionMap.get(bdName); //当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置 if (bd != null && beanName.equals(bd.getParentName())) { resetBeanDefinition(bdName); } } } }
方法13:resetBeanDefinition
public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { //如果别名缓存中已经存在该数据,则移除 if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { //如果别名已经注册过,直接返回 if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'"); } } //检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A checkForAliasCircle(name, alias); //加入缓存 this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
总结
至此,Spring 加载默认命名空间的 BeanDefinition 的过程就全部分析完了,可以说这是 BeanFactory 实例化前最复杂的逻辑了。我们梳理一下流程:
1、Spring判断是否默认命名空间,加载默认解析器进行解析
2、使用默认命名空间解析完成后得到初步的BeanDefinition对象,再调用自定义命名空间进行处理判断是否需要补充处理。
3、将解析的BeanDefinition 加入beanDefinitionMap缓存中,将beanName加入beanDefinitionNames缓存中,将aliases加入到aliasMap缓存中。
后面我们会继续讲解自定义命名空间的处理过程。