该系列文章是本人在学习 Spring 的过程当中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合个人源码注释 Spring 源码分析 GitHub 地址 进行阅读html
Spring 版本:5.1.14.RELEASEjava
开始阅读这一系列文章以前,建议先查看《深刻了解 Spring IoC(面试题)》这一篇文章node
该系列其余文章请查看:《死磕 Spring 之 IoC 篇 - 文章导读》git
上一篇文章《BeanDefinition 的加载阶段(XML 文件)》获取到 org.w3c.dom.Document
对象后,须要经过 DefaultBeanDefinitionDocumentReader 进行解析,解析出 XML 文件中定义的 BeanDefinition 并进行注册,先来回顾一下上一篇文章中的这段代码:github
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // <1> 建立 BeanDefinitionDocumentReader 对象 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // <2> 获取已注册的 BeanDefinition 数量 int countBefore = getRegistry().getBeanDefinitionCount(); // <3> 建立 XmlReaderContext 对象(读取 Resource 资源的上下文对象) // <4> 根据 Document、XmlReaderContext 解析出全部的 BeanDefinition 并注册 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // <5> 计算新注册的 BeanDefinition 数量 return getRegistry().getBeanDefinitionCount() - countBefore; }
本文开始分析第 4
步,BeanDefinition 的解析阶段,其中 BeanDefinitionDocumentReader 只有 DefaultBeanDefinitionDocumentReader 一个默认实现类面试
org.springframework.beans.factory.xml.BeanDefinitionDocumentReader
,解析 DOM document 中的 BeanDefinition 并注册,代码以下:spring
public interface BeanDefinitionDocumentReader { /** * Read bean definitions from the given DOM document and * register them with the registry in the given reader context. * @param doc the DOM document * @param readerContext the current context of the reader * (includes the target registry and the resource being parsed) * @throws BeanDefinitionStoreException in case of parsing errors */ void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException; }
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
,Spring 默认的 BeanDefinitionDocumentReader 实现类,从 XML 文件中解析出 BeanDefinition 并注册express
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { /** bean */ public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT; public static final String NESTED_BEANS_ELEMENT = "beans"; public static final String ALIAS_ELEMENT = "alias"; public static final String NAME_ATTRIBUTE = "name"; public static final String ALIAS_ATTRIBUTE = "alias"; public static final String IMPORT_ELEMENT = "import"; public static final String RESOURCE_ATTRIBUTE = "resource"; public static final String PROFILE_ATTRIBUTE = "profile"; @Nullable private XmlReaderContext readerContext; /** * XML 文件的 BeanDefinition 解析器 */ @Nullable private BeanDefinitionParserDelegate delegate; }
上面定义了 XML 文件中经常使用的标签缓存
registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法,根据 Document、XmlReaderContext 解析出全部的 BeanDefinition 并注册,方法以下:mybatis
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; // 得到 XML Document Root Element // 执行注册 BeanDefinition doRegisterBeanDefinitions(doc.getDocumentElement()); } /** * Register each bean definition within the given root {@code <beans/>} element. */ @SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...) protected void doRegisterBeanDefinitions(Element root) { // 记录老的 BeanDefinitionParserDelegate 对象,避免再次调用当前方法时解析出现问题(默认值可能不一样) BeanDefinitionParserDelegate parent = this.delegate; // <1> 建立 BeanDefinitionParserDelegate 对象 `delegate`,并初始化默认值 this.delegate = createDelegate(getReaderContext(), root, parent); // <2> 检查 <beans /> 根标签的命名空间是否为空,或者是 http://www.springframework.org/schema/beans if (this.delegate.isDefaultNamespace(root)) { // <2.1> 获取 `profile` 属性 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { // <2.2> 使用分隔符切分,可能有多个 `profile` String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. // <2.3> 根据 Spring Environment 进行校验,若是全部 `profile` 都无效,则不进行注册 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } // <3> 解析前处理 preProcessXml(root); // <4> 解析出 XML Document 中的 BeanDefinition 并注册 parseBeanDefinitions(root, this.delegate); // <5> 解析后处理 postProcessXml(root); // 设置 delegate 回老的 BeanDefinitionParserDelegate 对象 this.delegate = parent; }
首先获取 XML Document 的最顶层的标签,也就是 <beans />
,而后对其子标签进行解析,这里的过程大体以下:
delegate
,并初始化默认值<beans />
根标签是不是默认命名空间(xmlns 属性,为空或者是 http://www.springframework.org/schema/beans
),是的话进行校验
profile
属性,使用分隔符切分profile
都无效,则不进行注册parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法,解析 XML Document 的最顶层的标签,解析出 BeanDefinition 并注册,方法以下:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // <1> 若是根节点使用默认命名空间,执行默认解析 if (delegate.isDefaultNamespace(root)) { // <1.1> 遍历全部的子节点 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; // <1.2> 若是该节点使用默认命名空间,执行默认解析 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } // <1.3> 若是该节点非默认命名空间,执行自定义解析 else { delegate.parseCustomElement(ele); } } } } // <2> 若是根节点非默认命名空间,执行自定义解析 else { delegate.parseCustomElement(root); } }
解析过程大体以下:
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法BeanDefinitionParserDelegate#parseCustomElement(Element ele)
方法BeanDefinitionParserDelegate#parseCustomElement(Element ele)
方法命名空间是什么?
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.geekbang.thinking.in.spring.ioc.overview" /> <bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User"> <property name="id" value="1"/> <property name="name" value="小马哥"/> </bean> </beans>
在 XML 文件中的标签的 xmlns
能够定义默认的命名空间,xmlns:context
定义 context
的命名空间,xsi:schemaLocation
定义了命名空间对应的 XSD 文件(校验 XML 内容)。
上面的 <beans />
和 <bean>
标签的命名空间为 http://www.springframework.org/schema/beans
,其中 <context:component-scan />
标签的命名空间为 http://www.springframework.org/schema/context
(不是默认命名空间)
本文主要分析默认命名空间的解析过程,其余命名空间(注解相关)在后面进行分析,基于 Extensible XML authoring 扩展 Spring XML 元素会进入这里,主要是经过 NamespaceHandler 这个接口实现的。例如 Spring 集成 Mybatis 项目中的 <mybatis:scan />
就是扩展 Spring XML 元素,具体实如今后面分析;Spring 的<context:component-scan />
最终会经过 ComponentScanBeanDefinitionParser 进行解析。ComponentScanBeanDefinitionParser 是将 @Component 注解标注的类转换成 BeanDefinition 的解析器。
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法,处理默认命名空间的节点,方法以下:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 解析 `<import />` importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 解析 `<alias />`,将 name 对应的 alias 别名进行注册 processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 解析 `<bean />` processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 循环处理,解析 `<beans />` doRegisterBeanDefinitions(ele); } }
解析下面四种标签:
<import />
标签,例如这么配置:<import resource="dependency-lookup-context.xml"/>
,那么这里会获取到对应的 XML 文件,而后进行相同的处理过程
<alias />
标签,将 name 对应的 alias 别名进行注册,往 AliasRegistry 注册(BeanDefinitionRegistry 继承了它),也就是说你能够经过别名找到对应的 Bean
<bean />
标签,解析成 BeanDefinition 并注册,调用 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
方法
<beans />
标签,循环处理,和前面的步骤相同
processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
方法,将 <bean />
标签解析成 BeanDefinition 并注册,方法以下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // <1> 解析 `<bean />` 标签,返回 BeanDefinitionHolder 对象(包含 BeanDefinition、beanName、aliases) BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // <2> 对该标签进行装饰,通常不会,暂时忽略 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // <3> 进行 BeanDefinition 的注册 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)); } }
过程以下:
<bean />
标签,返回 BeanDefinitionHolder 对象(包含 BeanDefinition、beanName、aliases),调用 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele)
方法org.springframework.beans.factory.xml.BeanDefinitionParserDelegate
,解析 XML Document 里面的 BeanDefinition
parseBeanDefinitionElement(Element ele)
方法,将 XML Document 里面的某个标签解析成 BeanDefinition,方法以下:
@Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { // <1> 计算 BeanDefinition 的 `beanName` 名称和 `aliases` 别名集合 // <1.1> 获取标签的 `id` 和 `name` 属性 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // <1.2> 将 `name` 属性所有添加至别名集合 List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } // <1.3> 设置 Bean 的名称,优先 `id` 属性,其次 `name` 属性 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"); } } // <1.4> 检查 `beanName` 的惟一性 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // <2> 解析 `<bean />` 标签相关属性,构造出一个 GenericBeanDefinition 对象 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { // <3> 若是不存在 `beanName`,则根据 Class 对象的名称生成一个 if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { // 内部 Bean // <3.1> 生成惟一的 `beanName` beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { // <3.2> 生成惟一的 beanName 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; } } // <4> 建立 BeanDefinitionHolder 对象,设置 `beanName` 名称和 `aliases` 别名集合,返回 String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
过程以下:
beanName
名称和 aliases
别名集合
id
和 name
属性name
属性所有添加至别名集合 aliases
beanName
,优先 id
属性,其次 name
属性beanName
的惟一性<bean />
标签相关属性,构造出一个 GenericBeanDefinition 对象,调用 parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
方法beanName
,则根据 Class 对象的名称生成一个beanName
名称和 aliases
别名集合,返回parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
方法,解析 <bean />
成 GenericBeanDefinition 对象,方法以下:
@Nullable public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); // <1> 获取 `class` 和 `parent` 属性 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 { // <2> 构建一个 GenericBeanDefinition 对象 `bd` AbstractBeanDefinition bd = createBeanDefinition(className, parent); // <3> 解析 `<bean />` 的各类属性并赋值 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 提取 description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // <4> 解析 `<bean />` 的子标签,生成的对象设置到 `bd` 中 // <4.1> 解析 `<meta />` 元数据标签 parseMetaElements(ele, bd); // <4.2> 解析 `<lookup-method />` 标签 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // <4.3> 解析 `<replaced-method />` 标签 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // <4.4> 解析 `<constructor-arg />` 构造函数的参数集合标签 parseConstructorArgElements(ele, bd); // <4.5> 解析 `<property />` 属性标签 parsePropertyElements(ele, bd); // <4.5> 解析 `<qualifier />` 标签 parseQualifierElements(ele, bd); // <5> 设置 Bean 的 `resource` 资源为 XML 文件资源 bd.setResource(this.readerContext.getResource()); // <6> 设置 Bean 的 `source` 来源为 `<bean />` 标签对象 bd.setSource(extractSource(ele)); return bd; } // ... 省略 catch 各类异常 finally { this.parseState.pop(); } return null; }
过程以下:
class
和 parent
属性bd
,设置 parentName
和 beanClass
(Class 对象)或者 className
(Class 名称)<bean />
的各类属性并赋值:scope、abstract、lazy-init、autowire、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method<bean />
的子标签,生成的对象设置到 bd
中
<meta />
元数据标签,将 key-value 保存至 Map 中<lookup-method />
标签,解析成 LookupOverride 对象,用于实现 Bean 中的某个方法<replaced-method />
标签,解析成 ReplaceOverride 对象,用于替换 Bean 中的某个方法<constructor-arg />
构造函数的参数集合标签,将各个参数解析出来,可根据 index 属性进行排序<property />
属性标签,将各个属性解析出来,每一个属性对应一个 PropertyValue,添加至 bd
的 MutablePropertyValues 属性中<qualifier />
标签,解析出须要注入的对象 AutowireCandidateQualifierresource
资源为 XML 文件资源source
来源为 <bean />
标签对象lookup-method,会被解析成 LookupOverride 对象,replaced-method 会被解析成 ReplaceOverride 对象,这两个标签不是很经常使用
lookup-method:例如一个在一个抽象类中定义了抽象方法,能够经过这个标签订义一个 Bean 实现这个方法,Spring 会动态改变抽象类该方法的实现
replace-method:经过这个标签订义一个 Bean,去覆盖对应的方法,Spring 会动态替换类的这个方法
org.springframework.beans.factory.support.BeanDefinitionReaderUtils
,BeanDefinition 的解析过程当中的工具类
registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
,注册 BeanDefinition,方法以下:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // <1> 注册 BeanDefinition // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // <2> 注册 alias 别名 // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
过程以下:
BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法BeanDefinitionRegistry#registerAlias(String name, String alias)
方法这里的 BeanDefinitionRegistry 实现类是 DefaultListableBeanFactory,它是 Spring 底层 IoC 容器,还继承了 SimpleAliasRegistry(AliasRegistry 实现类)
// org.springframework.beans.factory.support.DefaultListableBeanFactory @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // 校验 beanName 与 beanDefinition 非空 Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); // <1> 校验 BeanDefinition // 这是注册前的最后一次校验了,主要是对属性 methodOverrides 进行校验 if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } // <2> 从缓存中获取指定 beanName 的 BeanDefinition BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); // <3> 若是已经存在 if (existingDefinition != null) { // 若是存在可是不容许覆盖,抛出异常 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } // 覆盖 beanDefinition 大于 被覆盖的 beanDefinition 的 ROLE ,打印 info 日志 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 + "]"); } } // 覆盖 beanDefinition 与 被覆盖的 beanDefinition 不相同,打印 debug 日志 else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } // 其它,打印 debug 日志 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); } // <4> 若是未存在 else { // 检测建立 Bean 阶段是否已经开启,若是开启了则须要对 beanDefinitionMap 进行并发控制 if (hasBeanCreationStarted()) { // beanDefinitionMap 为全局变量,避免并发状况 // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { // 添加到 BeanDefinition 到 beanDefinitionMap 中 this.beanDefinitionMap.put(beanName, beanDefinition); // 添加 beanName 到 beanDefinitionNames 中 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 从 manualSingletonNames 移除 beanName removeManualSingletonName(beanName); } } else { // 添加到 BeanDefinition 到 beanDefinitionMap 中 // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); // 添加 beanName 到 beanDefinitionNames 中,保证注册顺序 this.beanDefinitionNames.add(beanName); // 从 manualSingletonNames 移除 beanName removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } // <5> 从新设置 beanName 对应的缓存 if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
逻辑不复杂,主要是对 beanName
和该 BeanDefinition 对象的校验,最终将其映射保存在 beanDefinitionMap
中(ConcurrentHashMap),key 就是 beanName
// org.springframework.core.SimpleAliasRegistry @Override public void registerAlias(String name, String alias) { // 校验 name 、 alias Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { // name == alias 则去掉alias if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { // 获取 alias 已注册的 beanName String registeredName = this.aliasMap.get(alias); // 已存在 if (registeredName != null) { // 相同,则 return ,无需重复注册 if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } // 不容许覆盖,则抛出 IllegalStateException 异常 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 + "'"); } } // 校验,是否存在循环指向 checkForAliasCircle(name, alias); // 注册 alias this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
逻辑不复杂,将 alias
与 beanName
映射保存至 aliasMap
中(ConcurrentHashMap)
解析出 XML 文件中的 BeanDefinition 并注册的整个过程大体以下:
org.w3c.dom.Document
对象<beans />
标签,遍历全部的子标签
http://www.springframework.org/schema/beans
)则进行处理,例如:<import>
、<alias />
、<bean />
和<beans />
,其中 <bean />
会被解析出一个 GenericBeanDefinition 对象,而后进行注册<context:component-scan />
、<context:annotation-config />
、<util:list />
,这些非默认命名空间的标签都会有对应的 BeanDefinitionParser 解析器至此,咱们经过 XML 文件定义的 Bean 已经转换成了 Bean 的“前身”,也就是 BeanDefinition 对象。接下来会分析在 XML 文件中,非默认命名空间的标签是如何进行处理的。