Spring(十)
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 手绘图~
评论