品牌营销型网站建设广西知名网站设计

张小明 2026/1/2 19:36:07
品牌营销型网站建设,广西知名网站设计,现在建网站多少钱, 天堂资源官网在线资源读取XML中的别名配置 回顾上一章节 在上一篇文章中#xff0c;我们深入探索了 Spring 如何从命名空间找到对应的解析器#xff1a; Spring 通过 parseCustomElement 方法解析非默认命名空间的标签通过 DefaultNamespaceHandlerResolver 加载 META-INF/spring.handlers 文件…读取XML中的别名配置回顾上一章节在上一篇文章中我们深入探索了 Spring 如何从命名空间找到对应的解析器Spring 通过parseCustomElement方法解析非默认命名空间的标签通过DefaultNamespaceHandlerResolver加载META-INF/spring.handlers文件建立命名空间到处理器的映射关系通过懒加载和缓存机制实现按需加载和性能优化通过策略模式和约定优于配置实现了灵活的扩展机制关键理解在解析 XML 配置时Spring 需要处理各种标签包括默认命名空间的bean、alias、import等标签。那么Spring 是如何处理alias标签为 Bean 定义别名的呢统一术语在开始之前我们先明确几个关键术语别名AliasBean 的另一个名称可以通过别名访问同一个 BeanBean 名称Bean NameBean 的唯一标识符通常通过id或name属性指定AliasRegistry别名注册表接口负责管理 Bean 的别名SimpleAliasRegistry别名注册表的简单实现使用 Map 存储别名映射关系BeanDefinitionRegistryBean 定义注册表继承自AliasRegistry负责注册和管理 Bean 定义问题场景当我们使用 Spring 时XML 配置文件中可以使用alias标签为 Bean 定义别名?xml version1.0 encodingUTF-8?beansxmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!-- 定义一个Bean --beaniduserServiceclasscom.example.UserService/!-- 为Bean定义别名 --aliasnameuserServicealiasuserServiceImpl/aliasnameuserServicealiasuserServiceBean//beans核心问题Spring 如何解析alias标签当遇到alias标签时Spring 是如何处理的别名是如何存储的Spring 使用什么数据结构来存储别名和 Bean 名称之间的映射关系别名是如何被使用的当我们通过别名获取 Bean 时Spring 是如何找到对应的 Bean 的别名和 Bean 名称有什么区别为什么需要别名别名有什么实际用途如何处理别名的循环引用如果别名 A 指向别名 B别名 B 又指向别名 ASpring 如何处理这些问题看似简单但深入思考会发现它们背后有一套清晰的机制。让我们从源码中寻找答案。源码探索第一步processAliasRegistration 方法的核心逻辑关键方法为processAliasRegistration(Element ele)。让我们看看这个方法做了什么protectedvoidprocessAliasRegistration(Elementele){// 获取 name 和 alias 的配置Stringnameele.getAttribute(NAME_ATTRIBUTE);Stringaliasele.getAttribute(ALIAS_ATTRIBUTE);// 如果存在空字符串则不注册booleanvalidtrue;if(!StringUtils.hasText(name)){getReaderContext().error(Name must not be empty,ele);validfalse;}if(!StringUtils.hasText(alias)){getReaderContext().error(Alias must not be empty,ele);validfalse;}if(valid){try{// 注册时通过上下文中的注册器注册别名getReaderContext().getRegistry().registerAlias(name,alias);}catch(Exceptionex){getReaderContext().error(Failed to register alias alias for bean with name name,ele,ex);}}}发现一方法的核心逻辑分为三步获取 name 和 alias 的配置从 XML 元素中获取name和alias属性验证配置如果存在空字符串则不注册并记录错误信息注册别名通过上下文中的注册器注册别名关键理解注册时通过上下文中的注册器注册别名。这里我们可以回顾一下一开始的XmlBeanFactory实际上就是一个AliasRegistry因为他是AliasRegistry接口的实现类。第二步理解 XmlBeanFactory 的继承关系我们再细看下这个类XmlBeanFactory继承了DefaultListableBeanFactoryDefaultListableBeanFactory实现了BeanDefinitionRegistryBeanDefinitionRegistry实现了AliasRegistry故拥有了注册别名的能力。让我们看看这个继承关系XmlBeanFactory extends DefaultListableBeanFactory implements BeanDefinitionRegistry extends AliasRegistry发现二通过这个继承链XmlBeanFactory最终拥有了AliasRegistry的能力可以注册和管理 Bean 的别名。类比理解这就像家族遗传XmlBeanFactory继承了父辈的能力最终拥有了处理别名的基因。思考时刻为什么 Spring 要设计这样的继承关系为什么不直接在XmlBeanFactory中实现AliasRegistry接口深入探索SimpleAliasRegistry 的作用但当我再去看实际注册别名的代码时又发现了另一个问题真正做事的是SimpleAliasRegistry而这个类和XmlBeanFactory的关系又不太好确定。发现五虽然XmlBeanFactory通过继承链拥有了AliasRegistry的能力但实际的别名注册逻辑是在SimpleAliasRegistry中实现的。关键理解SimpleAliasRegistry是AliasRegistry接口的默认实现它使用MapString, String来存储别名和 Bean 名称之间的映射关系。事已至此我觉得应该把这个类图拿出来了。让我们通过类图来清晰地展示这些类之间的关系发现六通过类图我们可以清晰地看到AliasRegistry定义了别名管理的接口规范SimpleAliasRegistry提供了别名管理的默认实现使用Map存储别名映射BeanDefinitionRegistry继承了AliasRegistry同时定义了 Bean 定义管理的接口DefaultListableBeanFactory实现了BeanDefinitionRegistry同时继承了SimpleAliasRegistry拥有了别名管理的具体实现XmlBeanFactory继承了DefaultListableBeanFactory因此也拥有了别名管理的能力关键理解DefaultListableBeanFactory通过继承SimpleAliasRegistry获得了别名管理的具体实现。这样设计的好处是职责分离SimpleAliasRegistry专注于别名管理代码复用多个类可以复用SimpleAliasRegistry的实现灵活扩展可以轻松替换不同的别名管理实现第三步深入理解 SimpleAliasRegistry 的注册逻辑所以我们重点看SimpleAliasRegistry这个就行。成员变量publicclassSimpleAliasRegistryimplementsAliasRegistry{// 存储别名与bean名的关系key是别名value是被代表的名字privatefinalMapString,StringaliasMapnewConcurrentHashMap(16);}发现七aliasMap成员变量存储了别名与被代表名字的关系。注意这里的 value 不一定是 bean 名也可能是别名因为别名可以指向别名关键理解其实我上面说的bean名并不一定对应该是被代表的名字该名字也可能是别名。因为 Spring 支持别名指向别名的情况。⚠️注意aliasMap使用ConcurrentHashMap实现保证了线程安全。key 是别名value 是被代表的名字可能是 bean 名也可能是另一个别名。注册方法的核心逻辑再看注册方法registerAlias(String name, String alias)publicvoidregisterAlias(Stringname,Stringalias){synchronized(this.aliasMap){// 1. 加同步锁保证多线程仅有一个线程操作aliasMap// 2. 判断别名是否与bean名相同相同则删除已有的别名缓存if(alias.equals(name)){this.aliasMap.remove(alias);}else{// 3. 从缓存中查询是否已存在该别名StringregisteredNamethis.aliasMap.get(alias);if(registeredName!null){// 存在并且bean名相同则结束if(registeredName.equals(name)){return;}// 存在但bean名不同则判断是否允许别名覆盖if(!allowAliasOverriding()){thrownewIllegalStateException(Cannot register alias alias for name name: It is already registered for name registeredName.);}}// 4. 检查是否存在别名循环checkForAliasCircle(name,alias);// 5. 一切顺利通过则将别名和被代表的名字放入缓存this.aliasMap.put(alias,name);}}}发现八注册方法的核心逻辑分为5步加同步锁使用synchronized (this.aliasMap)保证多线程环境下仅有一个线程操作aliasMap确保线程安全判断别名是否与被代表的名字相同如果别名和名字相同则删除已有的别名缓存因为不需要别名指向自己检查别名是否已存在从缓存中查询是否已存在该别名如果存在并且指向的名字相同则直接结束幂等性如果存在但指向的名字不同则判断是否允许别名覆盖通过allowAliasOverriding()方法这是一个 Spring 配置不允许则抛异常检查是否存在别名循环比如别名123 → 名字456别名456又代表名字123。这个判断也采用了递归可以细品一下这个逻辑。注册别名一切顺利通过则将别名和被代表的名字放入缓存关键理解这里的名字name不一定是 bean 名也可能是别名。因为 Spring 支持别名指向别名的情况所以需要递归检查循环引用。别名循环检测的递归逻辑让我们看看checkForAliasCircle方法是如何检测循环的protectedvoidcheckForAliasCircle(Stringname,Stringalias){if(hasAlias(alias,name)){thrownewIllegalStateException(Cannot register alias alias for name name: Circular reference - name is a direct or indirect alias for alias already);}}publicbooleanhasAlias(Stringname,Stringalias){StringregisteredNamethis.aliasMap.get(name);if(registeredNamenull){returnfalse;}if(registeredName.equals(alias)){returntrue;}// 递归检查如果name指向的名字也有别名继续递归检查returnhasAlias(registeredName,alias);}发现九别名循环检测采用了递归算法如果name已经指向了alias直接或间接则抛出异常通过递归调用hasAlias可以检测多层的别名循环类比理解这就像检查一个链条是否有环。如果 A 指向 BB 指向 CC 又指向 A就形成了一个环。递归检查就是沿着链条一直走下去如果最终回到了起点就说明有循环。思考时刻为什么需要检测别名循环如果不检测会有什么问题第四步通知别名注册的监听器最终通知别名注册的监听器。在registerAlias方法中Spring 会通知所有注册的监听器告知别名已经注册。这允许其他组件如 Spring 的工具类、扩展点等在别名注册时执行相应的操作。发现三Spring 通过监听器机制实现了别名注册的扩展点。当别名注册完成后所有注册的监听器都会被通知可以进行相应的处理。关键理解这种监听器机制是 Spring 框架中常见的扩展模式允许其他组件在关键操作发生时得到通知并执行相应的逻辑。监听器的默认实现和扩展方式其实这监听器也很有意思默认是EmptyReaderEventListener里面都是空方法实现。如果需要重写则需要实现ReaderEventListener接口并在初始化XmlBeanFactory时将自定义的实现 set 进去。// 默认实现空方法publicclassEmptyReaderEventListenerimplementsReaderEventListener{OverridepublicvoiddefaultsRegistered(DefaultsDefinitiondefaultsDefinition){// 空实现}OverridepublicvoidcomponentRegistered(ComponentDefinitioncomponentDefinition){// 空实现}OverridepublicvoidaliasRegistered(AliasDefinitionaliasDefinition){// 空实现}OverridepublicvoidimportProcessed(ImportDefinitionimportDefinition){// 空实现}}发现四Spring 通过空对象模式Null Object Pattern提供了一个默认的监听器实现。这样即使没有自定义监听器代码也能正常运行不会出现空指针异常。扩展方式如果需要自定义监听器需要实现ReaderEventListener接口在初始化XmlBeanFactory时通过setEventListener方法设置自定义实现思考时刻对于ApplicationContext是更高级的BeanFactory他是否提供了更加优雅更加方便的实现方式呢类比理解就像发布订阅模式当别名注册这个事件发生时所有订阅了这个事件的监听器都会收到通知。默认情况下Spring 提供了一个空订阅者EmptyReaderEventListener它什么都不做但保证了系统的正常运行。设计思想1. 继承链的设计Spring 通过精心设计的继承链让XmlBeanFactory最终拥有了别名管理的能力XmlBeanFactory extends DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory extends AbstractBeanFactory extends FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements AliasRegistry发现这种设计的好处是职责分离每个类都有明确的职责SimpleAliasRegistry专注于别名管理代码复用多个类可以复用SimpleAliasRegistry的实现灵活扩展可以轻松替换不同的别名管理实现类比理解这就像搭积木每一层都有自己的功能最终搭成了一个完整的房子BeanFactory。2. 线程安全设计SimpleAliasRegistry使用synchronized关键字和ConcurrentHashMap来保证线程安全同步锁在registerAlias方法中使用synchronized (this.aliasMap)保证多线程环境下仅有一个线程操作aliasMap并发集合使用ConcurrentHashMap作为存储结构提供了更好的并发性能关键理解这种设计既保证了线程安全又兼顾了性能。在高并发场景下ConcurrentHashMap的性能比普通的HashMap加锁要好。3. 防御性编程Spring 在别名注册时进行了多重检查空值检查检查 name 和 alias 是否为空重复检查检查别名是否已存在处理重复注册的情况循环检测使用递归算法检测别名循环引用覆盖控制通过allowAliasOverriding()配置控制是否允许别名覆盖发现这种防御性编程的思想让 Spring 能够优雅地处理各种边界情况提高了系统的健壮性。类比理解就像过安检需要检查身份证空值检查、检查是否重复进入重复检查、检查是否有危险品循环检测、检查是否允许进入覆盖控制。4. 递归算法的应用别名循环检测使用了递归算法能够检测多层的别名循环// 递归检查如果name指向的名字也有别名继续递归检查returnhasAlias(registeredName,alias);发现递归算法的优势是能够处理任意深度的别名链但需要注意避免栈溢出虽然在实际场景中别名链的深度通常不会很深。关键理解递归算法在这里非常适合因为别名链的结构本身就是递归的别名可以指向别名形成链式结构。5. 空对象模式Spring 通过EmptyReaderEventListener实现了空对象模式Null Object Pattern提供了一个默认的监听器实现。这样即使没有自定义监听器代码也能正常运行不会出现空指针异常。类比理解就像默认的空订阅者它什么都不做但保证了系统的正常运行。这比使用null更安全避免了空指针异常。6. 扩展点设计Spring 通过监听器机制提供了扩展点允许开发者在别名注册时执行自定义逻辑默认实现EmptyReaderEventListener提供空实现扩展方式实现ReaderEventListener接口在初始化时设置自定义实现发现这种设计让 Spring 既提供了默认行为又允许开发者根据需要扩展功能。大白话总结让我们用大白话再梳理一遍1. 这篇文章讲的是什么简单说Spring 如何解析 XML 中的alias标签为 Bean 定义别名以及别名是如何存储和管理的。类比就像给一个人起外号这个人Bean有一个正式名字bean name但也可以有多个外号别名。Spring 需要记住这些外号和正式名字的对应关系。2. 别名是如何被解析的简单说解析 XML 标签Spring 通过processAliasRegistration方法解析alias标签获取name和alias属性验证配置检查 name 和 alias 是否为空如果为空则不注册注册别名通过上下文中的注册器实际上是XmlBeanFactory注册别名类比就像登记外号需要先看看外号和正式名字是否都填写了然后才能登记。3. 别名是如何存储的简单说存储结构使用MapString, String实际上是ConcurrentHashMap存储别名映射关系key 是别名Map 的 key 是别名value 是被代表的名字Map 的 value 是被代表的名字可能是 bean 名也可能是另一个别名类比就像一本外号字典通过外号key可以查到对应的正式名字value。4. 注册别名时做了什么检查简单说同步锁保证多线程环境下只有一个线程在操作相同检查如果别名和名字相同则删除已有的别名缓存重复检查检查别名是否已存在如果存在且指向的名字相同则直接结束如果指向的名字不同则判断是否允许覆盖循环检测使用递归算法检测别名循环如 A→BB→A注册一切顺利通过则将别名和名字放入缓存类比就像登记外号时的多重检查不能重复登记重复检查、不能形成循环循环检测、需要保证安全同步锁。5. 为什么要检测别名循环简单说如果不检测别名循环可能会导致无限递归最终导致栈溢出或死循环。类比就像两个人互相给对方起外号A 的外号是 BB 的外号是 A这样就形成了一个循环。如果不检测查找时就会一直循环下去。6. 监听器是做什么的简单说监听器是一个扩展点当别名注册完成时会通知所有注册的监听器。默认情况下Spring 提供了一个空监听器EmptyReaderEventListener它什么都不做但保证了系统的正常运行。类比就像发布订阅模式当别名注册这个事件发生时所有订阅了这个事件的监听器都会收到通知。默认情况下Spring 提供了一个空订阅者它什么都不做但保证了系统的正常运行。总结通过这篇文章我们深入探索了 Spring 如何读取 XML 中的别名配置核心流程解析 XML 标签通过processAliasRegistration方法解析alias标签获取name和alias属性验证配置检查 name 和 alias 是否为空如果为空则不注册注册别名通过上下文中的注册器XmlBeanFactory注册别名实际注册SimpleAliasRegistry负责实际的别名注册逻辑通知监听器注册完成后通知所有注册的监听器关键设计继承链设计通过精心设计的继承链让XmlBeanFactory最终拥有了别名管理的能力线程安全使用synchronized和ConcurrentHashMap保证线程安全防御性编程进行多重检查空值检查、重复检查、循环检测、覆盖控制递归算法使用递归算法检测别名循环引用空对象模式通过EmptyReaderEventListener实现空对象模式扩展点设计通过监听器机制提供扩展点核心数据结构aliasMapConcurrentHashMapString, String存储别名与被代表名字的映射关系key别名value被代表的名字可能是 bean 名也可能是另一个别名关键方法processAliasRegistration(Element ele)解析 XML 标签获取配置调用注册器注册别名registerAlias(String name, String alias)注册别名的核心方法包含5个步骤的检查checkForAliasCircle(String name, String alias)检查别名循环hasAlias(String name, String alias)递归检查是否存在别名关系思考题为什么 Spring 要设计这样的继承链为什么不直接在XmlBeanFactory中实现AliasRegistry接口为什么需要检测别名循环如果不检测会有什么问题ConcurrentHashMap和synchronized一起使用是否多余为什么 Spring 要这样设计递归算法在检测别名循环时如何避免栈溢出在实际场景中别名链的深度通常是多少对于ApplicationContext是更高级的BeanFactory他是否提供了更加优雅更加方便的实现方式呢延伸阅读Spring 源码AliasRegistrySpring 源码SimpleAliasRegistrySpring 源码BeanDefinitionParserDelegateSpring 源码ReaderEventListenerSpring 源码EmptyReaderEventListener上一篇文章XML命名空间到标签解析
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

个人简单网站页如何建设一个收费的影视图文网站

分布式文件系统配置与服务器备份恢复指南 1. 分布式文件系统(DFS)的潜力与配置 DFS 具有强大的功能,当存在多个托管共享数据的目标位置时,可在 DFS 命名空间中为同一文件夹配置多个目标。命名空间会根据用户的站点信息,将用户请求路由到合适的文件夹目标,从而维护多个包…

张小明 2025/12/31 9:54:20 网站建设

邯郸企业网站建设价格机械设备网站

在智能制造的浪潮中,工业传感器如同精密的神经末梢,为生产线注入智慧与效率。而在众多传感器类型中,贝弗德激光对射式光电传感器凭借其毫米级精度、毫秒级响应和抗干扰能力,成为物流分拣、安全防护、环境监测等领域的“隐形守护者…

张小明 2025/12/27 19:30:29 网站建设

设计师做兼职的网站新人做网络咨询的网站

鸿蒙远程真机工具HOScrcpy:60fps流畅投屏开发指南 【免费下载链接】鸿蒙远程真机工具 该工具主要提供鸿蒙系统下基于视频流的投屏功能,帧率基本持平真机帧率,达到远程真机的效果。 项目地址: https://gitcode.com/OpenHarmonyToolkitsPlaza…

张小明 2025/12/27 13:27:50 网站建设

厚街做网站公司修改wordpress的首页

MetaRTC终极入门指南:5分钟快速上手跨平台WebRTC开发 【免费下载链接】metaRTC A cross-platform webRTC SDK 项目地址: https://gitcode.com/gh_mirrors/me/metaRTC 想要快速掌握跨平台WebRTC开发技术吗?MetaRTC作为一款功能强大的开源WebRTC SD…

张小明 2025/12/27 18:51:18 网站建设

上海网站设计住房建设和城乡管理局官网

1. Fasttext1.1 模型架构Fasttext模型架构和Word2vec的CBOW模型架构非常相似,下面就是FastText模型的架构图:从上图可以看出来,Fasttext模型包括输入层、隐含层、输出层共三层。其中输入的是词向量,输出的是label,隐含…

张小明 2025/12/27 17:18:56 网站建设

报名网站开发多钱优书网推书

Awk编程:关系与布尔运算符、文件信息处理及格式化输出 1. 关系与布尔运算符 关系和布尔运算符在数据处理中用于比较两个表达式。以下是详细介绍: - 关系运算符 | 运算符 | 描述 | | — | — | | < | 小于 | | > | 大于 | | <= | 小于或等于 | | >= | …

张小明 2025/12/26 15:20:40 网站建设