/** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); }
/** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 1 // 解析 id 属性 Stringid= ele.getAttribute(ID_ATTRIBUTE); // 解析 name 属性 StringnameAttr= ele.getAttribute(NAME_ATTRIBUTE); // 分割 name 属性 List<String> aliases = newArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); }
StringbeanName= id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { 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) { checkNameUniqueness(beanName, aliases, ele); }
AbstractBeanDefinitionbeanDefinition= parseBeanDefinitionElement(ele, beanName, containingBean); // 2 if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { // 3 // 如果不存在 beanName 那么根据 Spring 中提供的命名规则为当前 bean 生成对应的 beanName try { if (containingBean != null) { 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. StringbeanClassName= beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { 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); returnnull; } } String[] aliasesArray = StringUtils.toStringArray(aliases); returnnewBeanDefinitionHolder(beanDefinition, beanName, aliasesArray); // 4 }
/*parseBeanDefinitionElement*/ /** * Parse the bean definition itself, without regard to name or aliases. May return * {@code null} if problems occurred during the parsing of the bean definition. */ public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(newBeanEntry(beanName));
StringclassName=null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); }
/** * Create a bean definition for the given class name and parent name. * @param className the name of the bean class * @param parentName the name of the bean's parent bean * @return the newly created bean definition * @throws ClassNotFoundException if bean class resolution was attempted but failed */ protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); } /** * Create a new GenericBeanDefinition for the given parent name and class name, * eagerly loading the bean class if a ClassLoader has been specified. * @param parentName the name of the parent bean, if any * @param className the name of the bean class, if any * @param classLoader the ClassLoader to use for loading bean classes * (can be {@code null} to just register bean classes by name) * @return the bean definition * @throws ClassNotFoundException if the bean class could not be loaded */ publicstatic AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader)throws ClassNotFoundException {
/** * Apply the attributes of the given bean element to the given bean * definition. * @param ele bean declaration element * @param beanName bean name * @param containingBean containing bean definition * @return a bean definition initialized according to the bean element attributes */ public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 解析 singleton 属性。已废弃,使用 scope 设置 if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } // 解析 scope 属性 // https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/core.html#beans-factory-scopes elseif (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } elseif (containingBean != null) { // Take default from containing bean in case of an inner bean definition. // 在嵌入 beanDefinition 情况下且没有单独指定 scope 属性则使用父类默认的属性 bd.setScope(containingBean.getScope()); }
Finally, the bean definitions should contain matching qualifier values. This example also demonstrates that bean meta attributes may be used instead of the <qualifier/> sub-elements.If available, the <qualifier/> and its attributes would take precedence, but the autowiring mechanism will fallback on the values provided within the <meta/> tags if no such qualifier is present
/** * Get the value of a property element. May be a list etc. * Also used for constructor arguments, "propertyName" being null in this case. */ public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { StringelementName= (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
// Should only have one child element: ref, value, list, etc. // 一个属性只能对应一种类型:ref、value、list等 NodeListnl= ele.getChildNodes(); ElementsubElement=null; for (inti=0; i < nl.getLength(); i++) { Nodenode= 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) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } // 解析 constructor-arg 上的 ref 属性 booleanhasRefAttribute= ele.hasAttribute(REF_ATTRIBUTE); // 解析 constructor-arg 上的 value 属性 booleanhasValueAttribute= ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { /** 在 constructor-arg 上不存在: 1. 同时既有 ref 属性又有 value 属性 2. 存在 ref 属性或者 value 属性且又有子元素 **/ error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); }
if (hasRefAttribute) { // ref 属性的处理,使用 RuntimeBeanRefence 封装对应的 ref 名称 StringrefName= ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReferenceref=newRuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } elseif (hasValueAttribute) { // value 属性的处理,使用 TypedStringValue 封装 TypedStringValuevalueHolder=newTypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } elseif (subElement != null) { // 解析子元素 return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. // 即没有 ref 也没有 value 也没有子元素,报错 error(elementName + " must specify a ref or value", ele); returnnull; } }
/** * Parse a value, ref or collection sub-element of a property or * constructor-arg element. * @param ele subelement of property element; we don't know which yet * @param defaultValueType the default type (class name) for any * {@code <value>} tag that might be created */ public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } elseif (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHoldernestedBd= parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } elseif (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. StringrefName= ele.getAttribute(BEAN_REF_ATTRIBUTE); booleantoParent=false; if (!StringUtils.hasLength(refName)) { // 解析 local // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // 解析 parent // 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); returnnull; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); returnnull; } RuntimeBeanReferenceref=newRuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } // 对 idref 元素的解析 elseif (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } // 对 value 子元素的解析 elseif (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } // 对 null 子元素的解析 elseif (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. TypedStringValuenullHolder=newTypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } // 解析 array 子元素 elseif (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } // 解析 list 子元素 elseif (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } // 解析 set 子元素 elseif (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } // 解析 map 子元素 elseif (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } // 解析 parse 子元素 elseif (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); returnnull; } }
/** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ publicstaticvoidregisterBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
@Override publicvoidregisterAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); // 如果 beanName 与 alias 相同的话不记录 alias,并删除对应的 alias if (alias.equals(name)) { this.aliasMap.remove(alias); } else { StringregisteredName=this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } // 如果 alias 不允许被覆盖则抛出异常 if (!allowAliasOverriding()) { thrownewIllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } } // 当 A->B 存在时,若再次出现 A->C->B 时候则会抛出异常 checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); } }
alias 与 beanName 相同情况处理。若 alias 与 beanName 并名称相同则不需要处理并删除掉原有 alias。
alias 覆盖处理。若 aliasName 已经使用并已经指向了另一 beanName 则需要用户的设置进行处理。
/** * Process the given alias element, registering the alias with the registry. */ protectedvoidprocessAliasRegistration(Element ele) { // 获取 beanName Stringname= ele.getAttribute(NAME_ATTRIBUTE); // 获取 alias Stringalias= ele.getAttribute(ALIAS_ATTRIBUTE); booleanvalid=true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { // 注册 alias getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } // 别名注册后通知监听器做相应处理 getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } }
/** * Parse an "import" element and load the bean definitions * from the given resource into the bean factory. */ protectedvoidimportBeanDefinitionResource(Element ele) { // 获取 resource 属性 Stringlocation= ele.getAttribute(RESOURCE_ATTRIBUTE); // 如果不存在 resource 属性则不做任何处理 if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; }
// Resolve system properties: e.g. "${user.dir}" // 解析系统属性,格式如:"${user.dir}" location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
// Discover whether the location is an absolute or relative URI // 判定 location 是决定 URI 还是相对 RUI booleanabsoluteLocation=false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { // cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:" }
// Absolute or relative? if (absoluteLocation) { try { intimportCount= getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { // No URL -> considering resource location as relative to the current file. // 如果是相对地址则根据相对地址计算出绝对地址 try { int importCount; // Resource 存在多个子实现类,如 VfsResource,FileSystemResource 等, // 而每个 resource 的 createRelative 方式实现都不一样,所以这里先使用子类的方法尝试解析 ResourcerelativeResource= getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { // 如果解析不成功,则使用默认的解析器 ResourcePatternResolver 进行解析 StringbaseLocation= getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } // 解析后进行监听器激活处理 Resource[] actResArray = actualResources.toArray(newResource[actualResources.size()]); getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); }
/** * Register each bean definition within the given root {@code <beans/>} element. */ protectedvoiddoRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegateparent=this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) { StringprofileSpec= root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } }