Spring IOC源码篇五 核心方法obtainFreshBeanFactory.doLoadBeanDefinitions
XmlBeanDefinitionReader.doLoadBeanDefinitions
- 1.XmlBeanDefinitionReader.doLoadBeanDefinitions方法
- 2.XmlBeanDefinitionReader.doLoadDocument方法
- 3.DefaultDocumentLoader.loadDocument方法
- 4.XmlBeanDefinitionReader.registerBeanDefinitions方法(回到步骤1)
- 5.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions方法
- 6.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
- 7.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
- 8.DefaultBeanDefinitionDocumentReader.processAliasRegistration方法
- 9.DefaultBeanDefinitionDocumentReader.processBeanDefinition方法
- 10.BeanDefinitionReaderUtils.registerBeanDefinition方法
1.XmlBeanDefinitionReader.doLoadBeanDefinitions方法
doLoadBeanDefinitions才开始真正的加载bean定义信息(后续均称之为BeanDefinition)。后续大家会看到很多以do开头的方法,看到这种方法大家就需要重点关注,do开头的方法才是真正干活的。
/*** 将 XML 资源解析为 DOM 文档(Document),并进一步将文档内容转换为* BeanDefinition 注册到容器中。它是 XML 配置文件解析为 Spring 可* 管理 Bean 定义的核心*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 将XML资源解析为DOM文档对象Document doc = doLoadDocument(inputSource, resource);// 从文档中解析并注册Bean定义,返回注册的数量int count = registerBeanDefinitions(doc, resource);if (logger.isDebugEnabled()) {logger.debug("Loaded " + count + " bean definitions from " + resource);}return count;}// 抛出BeanDefinitionStoreException异常catch (BeanDefinitionStoreException ex) {throw ex;}// XML解析时的语法错误(如标签未闭合)catch (SAXParseException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);}// 其他XML解析异常(如DTD/XSD验证失败)catch (SAXException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"XML document from " + resource + " is invalid", ex);}// XML解析器配置异常(如不支持的特性)catch (ParserConfigurationException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Parser configuration exception parsing XML from " + resource, ex);}// IO异常(如资源无法读取)catch (IOException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"IOException parsing XML document from " + resource, ex);}// 其他未预期的异常catch (Throwable ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Unexpected exception parsing XML document from " + resource, ex);}
}
2.XmlBeanDefinitionReader.doLoadDocument方法
这里提一点,由于源码比较复杂。导致大家经常在看到对象属性的时候不知道在哪里赋值的,这个比较重要。所以大家在看源码的时候看到一些赋值的地方更应该重视,可能当时看觉得不起眼,后面这些赋值都是会被用到的。比较重要的属性赋值位置我会在代码里提到
/*** documentLoader解析XML*/
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,getValidationModeForResource(resource), isNamespaceAware());
}/*** getEntityResolver方法,获取EntityResolver,* 这里entityResolver != null,这里我想说的是这个entityResolver是在哪里被赋值。* 在上一篇文章中的* AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法* beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));*/
protected EntityResolver getEntityResolver() {// 若实体解析器未初始化,则创建默认实例,实际上这里entityResolver不等于nullif (this.entityResolver == null) {// 获取资源加载器(通常是当前ApplicationContext)ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader != null) {// 若存在资源加载器,使用ResourceEntityResolverthis.entityResolver = new ResourceEntityResolver(resourceLoader);}else {// 若不存在资源加载器,使用DelegatingEntityResolverthis.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());}}return this.entityResolver;
}/*** getValidationModeForResource方法,确定XML资源验证模式* XML 验证模式:* VALIDATION_NONE:无验证:不检查 XML 是否符合任何 DTD/XSD 约束,仅解析基本语法* VALIDATION_DTD:DTD 验证:基于 XML 头部的 DTD 声明(如 <!DOCTYPE beans ...>)验证* VALIDATION_XSD:XSD 验证:基于 XML 中的 XSD 命名空间(如 xmlns:xsi)验证* VALIDATION_AUTO:自动检测:未显式指定模式时的默认值,需通过后续逻辑判断* 最终我们使用的是 VALIDATION_XSD*/
protected int getValidationModeForResource(Resource resource) {// 在前面赋值了validationMode = VALIDATION_AUTOint validationModeToUse = getValidationMode();if (validationModeToUse != VALIDATION_AUTO) {return validationModeToUse;}// 推断当前验证模式,这里可以自己点进去看下int detectedMode = detectValidationMode(resource);if (detectedMode != VALIDATION_AUTO) {return detectedMode;}// 检测失败时,默认使用XSD验证:通常未检测到DTD声明时,XML更可能使用XSD约束return VALIDATION_XSD;
}
3.DefaultDocumentLoader.loadDocument方法
/*** XML输入源解析为Document文档对象*/
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {// 创建解析器工厂DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);if (logger.isTraceEnabled()) {logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");}// 创建解析器DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);// 解析器解析输入源,返回Document对象,具体的解析源码可自行查看。这里就不在讲解return builder.parse(inputSource);}
4.XmlBeanDefinitionReader.registerBeanDefinitions方法(回到步骤1)
/*** 解析XML文档(Document)转换为 BeanDefinition 并注册到 Spring 容器中*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {// 创建BeanDefinitionDocumentReader实例(默认实现为DefaultBeanDefinitionDocumentReader)BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();// 记录注册前容器中已有的BeanDefinition数量int countBefore = getRegistry().getBeanDefinitionCount();// 委托文档阅读器解析XML文档并注册BeanDefinitiondocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 返回本次新增的BeanDefinition数量(注册后总数 - 注册前总数)return getRegistry().getBeanDefinitionCount() - countBefore;
}/*** XML输入源解析为Document文档对象*/
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;// do开头的方法真正完成注册步骤开始,通过documentElementdoRegisterBeanDefinitions(doc.getDocumentElement());
}/*** 在给定的根<beans/>元素中注册每个bean定义*/
protected void doRegisterBeanDefinitions(Element root) {// 管理解析代理(delegate)的状态,支持嵌套<beans>标签的递归解析BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(getReaderContext(), root, parent);// 处理<beans>标签的profile属性,实现环境隔离,一般不会设定if (this.delegate.isDefaultNamespace(root)) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);// 检查当前环境是否匹配指定的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;}}}// 解析前的预处理(扩展点)preProcessXml(root);// 解析根元素下的所有子元素(核心逻辑),传入根节点<beans>,解析代理parseBeanDefinitions(root, this.delegate);// 解析后的后处理(扩展点)postProcessXml(root);// 恢复解析代理的状态(支持嵌套解析)this.delegate = parent;
}
5.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions方法
/*** 解析根元素下的所有子元素(如 <bean>、<import>、<context:component-scan> 等),* 是真正执行 Bean 定义提取的逻辑*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {// 这里说明下命名空间:就是我们在application-beans.xml文件中的// xmlns="http://www.springframework.org/schema/beans"(默认命名空间)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>、<import>、<alias>、<beans>)parseDefaultElement(ele, delegate);}else {// 解析自定义命名空间的元素(如<context:component-scan>)delegate.parseCustomElement(ele);}}}}else {// 根元素属于自定义命名空间时,直接解析delegate.parseCustomElement(root);}
}
6.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
/*** 解析默认命名空间(http://www.springframework.org/schema/beans)标签,* DefaultBeanDefinitionDocumentReader这里就可以看到大家在xml中配置的各* 种标签,熟悉的味道*/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {// 处理<import>标签:导入其他XML配置文件// 例如:<import resource="classpath:service.xml"/>importBeanDefinitionResource(ele);}// 处理<alias>标签:为已注册的Bean定义别名// 例如:<alias name="userService" alias="userServiceAlias"/>else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}// 处理<bean>标签:解析并注册Bean定义(核心逻辑)else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}// 处理<beans>标签:递归解析嵌套的配置else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// 递归调用doRegisterBeanDefinitions解析嵌套的<beans>// 递归到本类中的doRegisterBeanDefinitions(Element root)// spring中很多递归都不是简单的递归本方法,这点需要注意doRegisterBeanDefinitions(ele);}
}
7.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
/*** 解析 <import> 标签的 resource 属性,定位并加载目标配置文件,* 将其中的 Bean 定义合并到当前容器中。* 例如:<import resource="classpath:service.xml"/>*/
protected void importBeanDefinitionResource(Element ele) {// 获取<import>标签的resource属性值(目标配置文件路径)String location = ele.getAttribute(RESOURCE_ATTRIBUTE);if (!StringUtils.hasText(location)) {// 路径为空时抛出错误getReaderContext().error("Resource location must not be empty", ele);return;}// 解析路径中的系统属性占位符(如${user.dir})location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);// 存储实际加载的资源(可能包含通配符匹配的多个资源)Set<Resource> actualResources = new LinkedHashSet<>(4);// 判断路径是否为绝对路径(URL或绝对URI)boolean absoluteLocation = false;try {// 若路径是URL(如file:、http:)或绝对URI,则视为绝对路径absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();}catch (URISyntaxException ex) {// 无法转换为URI时,视为相对路径(除非是classpath*:前缀)}// 处理绝对路径资源if (absoluteLocation) {try {// 加载绝对路径资源中的Bean定义,返回加载数量// 这里又调用到上一篇中的AbstractBeanDefinitionReader.loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)方法中,可以理解成递归了int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);if (logger.isTraceEnabled()) {logger.trace("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 {// 处理相对路径资源try {int importCount;// 创建相对于当前资源的相对资源(如当前文件在classpath:spring/下,导入"service.xml"则定位到classpath:spring/service.xml)Resource relativeResource = getReaderContext().getResource().createRelative(location);if (relativeResource.exists()) {// 相对资源存在时,直接加载importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);actualResources.add(relativeResource);}else {// 相对资源不存在时,基于当前资源的URL构建绝对路径String baseLocation = getReaderContext().getResource().getURL().toString();importCount = getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);}if (logger.isTraceEnabled()) {logger.trace("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(new Resource[0]);getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
8.DefaultBeanDefinitionDocumentReader.processAliasRegistration方法
/*** 解析 <alias> 标签的 name 和 alias 属性,验证其合法性,将别名注册到容器中,* 并发布别名注册事件*/
protected void processAliasRegistration(Element ele) {// 提取<alias>标签的name和alias属性String name = ele.getAttribute(NAME_ATTRIBUTE);String alias = ele.getAttribute(ALIAS_ATTRIBUTE);// 验证属性合法性boolean valid = 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 {// 调用SimpleAliasRegistry注册别名,这里的getRegistry返回的就是在前面// AbstractRefreshableApplicationContext.refreshBeanFactory()中// DefaultListableBeanFactory beanFactory = createBeanFactory();// 创建的DefaultListableBeanFactory它继承了SimpleAliasRegistry// 它内部维护了一个ConcurrentHashMap,别名到名称的映射关系,这里可以自己点进去看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));}
}
9.DefaultBeanDefinitionDocumentReader.processBeanDefinition方法
这里大概讲解一下下面涉及到的一些知识点
GenericBeanDefinition:
Spring 解析 标签或 @Bean 注解时,首先生成 GenericBeanDefinition,再根据是否有父定义决定是否合并为 RootBeanDefinition,支持动态修改,可以理解成是BeanDefinition的一个中间态
RootBeanDefinition:
表示完全合并后的 Bean 定义,是 Spring 容器最终用于创建 Bean 实例的元数据。它通常是通过合并父 Bean 定义(parentName)和子 Bean 定义后生成的,不依赖其他 Bean 定义
lookup-method:
用于动态替换 Bean 中的抽象方法,使其返回指定的目标 Bean 实例。它的核心场景是:在单例 Bean 中获取原型(prototype)Bean—— 由于单例 Bean 初始化时仅创建一次,若直接在单例 Bean 中注入原型 Bean,后续每次使用的都是同一个原型实例;而通过 lookup-method 可确保每次调用方法时都获取到新的原型实例
lookup-method原理:
通过 CGLIB 动态代理 生成目标 Bean 的子类,重写 lookup-method 配置的抽象方法,在方法体内从 Spring 容器中获取指定的目标 Bean 并返回。
replaced-method:
用于完全替换 Bean 中的某个方法,即调用目标方法时,实际执行的是自定义的 “方法替换器” 逻辑,而非原方法逻辑。它的核心场景是:在不修改目标类源码的前提下,重写方法的实现(如修复旧代码的 bug、增强方法功能)。
replaced-method原理:
通过 MethodReplacer 接口 定义替换逻辑,在 Bean 初始化时,将自定义的 MethodReplacer 实例与目标方法关联。通过 CGLIB 生成目标 Bean 的代理类,重写目标方法,在代理方法中调用 MethodReplacer 的 reimplement 方法执行替换逻辑。
/*** 将 <bean> 标签解析为 BeanDefinition 及其元数据(名称、别名等),经过装饰增强后* 注册到容器,并发布注册事件*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {// 解析<bean>标签,生成包含BeanDefinition、名称和别名的封装对象(核心)BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {// 若需要,装饰BeanDefinition(如处理自定义属性或嵌套标签)bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// 将最终装饰后的BeanDefinition注册到容器BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}catch (BeanDefinitionStoreException ex) {// 注册失败时记录错误getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// 发布Bean注册完成事件getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}
}public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {return parseBeanDefinitionElement(ele, null);
}/*** 上面方法的重载* 解析 <bean> 标签的 id 和 name 属性以确定 Bean 名称和别名,校验名称唯一性,* 生成 BeanDefinition 实例,并最终封装为 BeanDefinitionHolder*/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {// 提取<bean>标签的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));}// 确定Bean的主名称(beanName)String beanName = id;// 若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");}}// 校验Bean名称和别名的唯一性if (containingBean == null) {checkNameUniqueness(beanName, aliases, ele);}// 解析<bean>标签的其他属性(如class、scope等),生成AbstractBeanDefinitionAbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);if (beanDefinition != null) {// 若主名称仍为空(id和name均未指定),自动生成Bean名称if (!StringUtils.hasText(beanName)) {try {if (containingBean != null) {// 嵌套Bean(如<bean><property><bean/></property></bean>),生成内部名称beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);}else {// 顶级Bean,通过readerContext生成名称beanName = this.readerContext.generateBeanName(beanDefinition);// 为兼容旧版本,若生成的名称包含类名,将类名作为别名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;}}// 将别名列表转换为数组,封装为BeanDefinitionHolder返回String[] aliasesArray = StringUtils.toStringArray(aliases);return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);}// 若解析失败(如缺少class属性),返回nullreturn null;
}/*** 上面方法的重载*/
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {// 记录解析状态(用于错误信息定位,如嵌套解析时的层级)this.parseState.push(new BeanEntry(beanName));// 提取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 {// 创建基础的BeanDefinition实例(GenericBeanDefinition)AbstractBeanDefinition bd = createBeanDefinition(className, parent);// 解析<bean>标签的核心属性(scope、lazy-init等)parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);// 解析description子元素(Bean描述信息)bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));// 解析各类子元素,完善BeanDefinition// <meta>标签:元数据(键值对),这里可以自行点进去查看具体的解析逻辑parseMetaElements(ele, bd);// <lookup-method>:方法查找注入,这里可以自行点进去查看具体的解析逻辑parseLookupOverrideSubElements(ele, bd.getMethodOverrides());// <replaced-method>:方法替换,这里可以自行点进去查看具体的解析逻辑parseReplacedMethodSubElements(ele, bd.getMethodOverrides());// <constructor-arg>:构造器注入,这里可以自行点进去查看具体的解析逻辑parseConstructorArgElements(ele, bd);// <property>:setter属性注入,这里可以自行点进去查看具体的解析逻辑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;
}
10.BeanDefinitionReaderUtils.registerBeanDefinition方法
回到第9步processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
BeanDefinitionHolder:
统一封装 BeanDefinition 实例、Bean 的主名称(beanName)和别名(aliases),确保这三者在传递和处理过程中不会分离
BeanDefinition容器:
DefaultListableBeanFactory中维护的beanDefinitionMap
BeanDefinition名称容器:
DefaultListableBeanFactory中维护的beanDefinitionNames
/*** 将 BeanDefinitionHolder 中封装的 Bean 主名称、BeanDefinition 和别名,* 分别注册到 BeanDefinitionRegistry 中*/
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {String beanName = definitionHolder.getBeanName();// 通过Bean的主名称,注册BeanDefinition到BeanDefinition容器中// 里面也会注册BeanDefinition名称到BeanDefinition名称容器中registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 若存在别名,为每个别名注册与主名称的映射String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {// 同第8步getReaderContext().getRegistry().registerAlias(name, alias);registry.registerAlias(beanName, alias);}}
}