写点什么

Spring(十)

  • 2022 年 4 月 15 日
  • 本文字数:2771 字

    阅读完需:约 9 分钟

  • alias

  • bean

  • beans


下面来看一下 alias 标签、import 标签如何解析的


[](()alias 标签解析




先去看下这个标签是如何进行使用的


<bean id="me" name="me0" class="xxx"/>


<alias name="me" alias="me1,me2"/>


在对 bean 提供名称的时候,Spring 支持提供多个名称,所以有了 alias 标签去为 bean 指定别名,alias 标签的 alias 的属性都指向同一个 bean,起 bean 的 id 为 me


下面就来看看容器是怎么解析 alias 标签的


对应的方法为 processAliasRegistration


源码如下


protected void processAliasRegistration(Element ele) {


//获取 alias 标签里面的属性


//获取 name 属性(name 属性为对应的 beanid)


String name = ele.getAttribute(NAME_ATTRIBUTE);


//获取 alias 属性(alias 属性为对应的别名)


String alias = ele.getAttribute(ALIAS_ATTRIBUTE);


//这个是一个校验操作结果标识


boolean valid = true;


//进行校验操作


//判断 name 属性和 alias 属性是否为空


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 标签没有进行复杂的解析


//这是因为 alias 标签就只有这两个属性


//使用 registrt 进行注册 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));


}


}


从代码上可以看到,对于 alias 标签没有 bean 标签的复杂,看到 bean 标签的解析流程,对于 alias 标签看起来就觉得很清秀


  • 获取 name、alias 属性

  • 进行校验操作

  • 校验通过就进行注册 alias 标签

  • 注册失败会抛错

  • alias 标签注册成功就通知监听器

  • 细节点:校验 alias 标签失败(name 属性为空或者 alias 属性为空),不会抛错。。

  • 注册工作交给 AliasRegistrt 接口(Bean 的注册交给 BeanDefinitionRegistry 接口)


对于 AliasRegistrt 接口



可以看到这个接口是被 BeanDefinitionRegistry 接口继承了,而其默认的实现类依然是 GenericApplicationContext


![在这里插入图片描述](https://img-blog.csdnimg.cn/b37df1512dfd4e18ab478426e77881d4.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_ 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 50,text_Q1NETiBAR0RVVF9FbWJlcg==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)


从代码上可以看到,GenericApplicationContext 依然将注册的工作交给 BeanFactory 去做(DefaultListableBeanFactory)



但 DefaultListableBeanFactory 并没有重写这个方法,反而是交给了其父类 SimpleAliasRegistry 去实现了,所以归根到底是 SimpleAliasRegistry 负责 Alias 标签的注册


解析的源码如下


@Override


public void registerAlias(String name, String alias) {


//校验判断为空


Assert.hasText(name, "'name' must not be empty");


Assert.hasText(alias, "'alias' must not be empty");


//进行底层的 aliasMap 进行加锁


//(ConcurrentHashMap 结构,而且这个容器在 SimpleAliasRegistry 中,默认容量为 16)


//同样 Spring


synchronized (this.aliasMap) {


Java 开源项目【ali1024.coding.net/public/P7/Java/git】 //如果 alias 属性与 name 属性相同


if (alias.equals(name)) {


//会删除掉原来的注册过的 alias 标签。。。


//不太理解这种做法


//alias 属性与 name 属性相等,其实就是没有起别名嘛


//而且 Spring 规定只有一个 alias 标签会起作用


//但干嘛要删除掉之前起的别名呢????


this.aliasMap.remove(alias);


if (logger.isDebugEnabled()) {


logger.debug("Alias definition '" + alias + "' ignored since it points to same name");


}


}


else {


// 如果 alias 与 name 属性不相同,证明 alias 标签是有效的


//从容器中获取这个 alias 标签对应的 name


String registeredName = this.aliasMap.get(alias);


//判断是否存在


if (registeredName != null) {


//如果存在且 name 是相同的


//就代表这个 alias 标签重复了


//不需要进行重复注册,省略,所以如果有重复的 alias 并不会报错


if (registeredName.equals(name)) {


// An existing alias - no need to re-register


return;


}


//如果 name 不相同,那就代表出现歧义了


//判断是否可以进行覆盖


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 + "'");


}


}


//再次检查判断 alias 标签是否注册


//这里判断蛮有意思的


checkForAliasCircle(name, alias);


//底层容器添加 alias,key 为 alias,value 为 name


this.aliasMap.put(alias, name);


if (logger.isTraceEnabled()) {


logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");


}


}


}


}


可以看到,其实 alias 的注册跟 beanDefinition 差不多


  • 校验 alias、name 属性是否为空,不为空才能继续进行下一步

  • 给底层容器进行上锁(明明已经是 ConcurrentHashMap,却还要进行 Synchronic 上锁处理,没必要吧)

  • 假如 name 和 alias 属性是相同的,代表 alias 标签是无效的,自己的别名起自己的名字?这是不符合常理的,所以,Spring 的处理是认为这个 alias 标签是取消别名设置,即不需要别名(给自己的别名取自己的名字,不就是不需要别名吗?),就会将这个 alias 的之前的别名清空掉

  • 假如不相同,代表 alias 标签是有效的,再判断之前是或否已经有注册过这个 alias

  • 如果注册过,判断是不是一样的 name,一样的话直接 Return

  • 不一样的话,判断支不支持覆盖,不支持覆盖会报错

  • 检查这个 alias 是否有循环引用问题

  • 往 aliasMap 添加 alias 与 name,alias 为 key,name 为 value

[](()检查是否有循环引用问题

最后

看完上述知识点如果你深感 Java 基础不够扎实,或者刷题刷的不够、知识不全面


小编专门为你量身定制了一套<Java 一线大厂高岗面试题解析合集:JAVA 基础-中级-高级面试+SSM 框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>



针对知识面不够,也莫慌!还有一整套的<Java 核心进阶手册>,可以瞬间查漏补缺



全都是一丢一丢的收集整理纯手打出来的


更有纯手绘的各大知识体系大纲,可供梳理:Java 筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的 xmind 手绘图~




用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
Spring(十)_面试_爱好编程进阶_InfoQ写作平台