使用Spring 的时候我们可以很容易的为某个bean 配置一个或多个别名

<bean id="app:dataSource" class="...">
<alias name="app:dataSoure" alias="user:dataSoure"/>
<alias name="app:dataSoure" alias="device:dataSoure"/>
</bean>

或者: 直接使用bean标签的name属性,就是别名 <bean id="aaa",name="bbb,ccc,ddd"/>

使用 @Bean 注解的时候

@Bean(value = {"aaa", "bbb", "ccc"})

那么 除了第一个是这个 beanName(bean id) 之外、其他的都是 alias

public interface AliasRegistry {
/**
* 为这个 name 注册一个 alias
*/
void registerAlias(String name, String alias);
/**
* 从注册表中移除这个alias对应的关系
*/
void removeAlias(String alias);
/**
* 给定的这个 name是否是一个 别名
*/
boolean isAlias(String name);
/**
* 根据这个 bean name 获取所有他的别名
*/
String[] getAliases(String name);
}

AliasRegistry 其中的一个实现类 SimpleAliasRegistry

private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

使用 Map 来存储、key 为 alias 、value 为 beanName (并不是意味着这个value只能是在spring 容器中存在的bean 的 id、也可以是一个 alias、比如说我对象A有个别名是小A、那么这个小A同样可以有它的别名小AA、那么Map的情况就是[(小A,对象A的id/beanName),(小AA,小A)] )

@Override
public void removeAlias(String alias) {
synchronized (this.aliasMap) {
String name = this.aliasMap.remove(alias);
if (name == null) {
throw new IllegalStateException("No alias '" + alias + "' registered");
}
}
} @Override
public boolean isAlias(String name) {
return this.aliasMap.containsKey(name);
} @Override
public String[] getAliases(String name) {
List<String> result = new ArrayList<>();
synchronized (this.aliasMap) {
retrieveAliases(name, result);
}
return StringUtils.toStringArray(result);
} /**
* Transitively retrieve all aliases for the given name.
*
* @param name the target name to find aliases for---bean name
* @param result the resulting aliases list
*/
private void retrieveAliases(String name, List<String> result) {
this.aliasMap.forEach((alias, registeredName) -> {
if (registeredName.equals(name)) {
result.add(alias);
retrieveAliases(alias, result);
}
});
}

上面的方法实现相对而已是比较简单的

@Override
public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty"); // 保证以下的操作都是原子性的、如果并发注册的话就会存在 循环引用的问题
synchronized (this.aliasMap) { if (alias.equals(name)) {
// 这一步是有必要这么做的、如果这个 alias 已经被其他的 bean 所使用、
// 那么我这个算是最新的了
// 至于为啥不放在 map 里面、因为key 和 value 一样的话、
// 后面的 getAliases 会死循环
this.aliasMap.remove(alias);
} else {
// 根据这个 alias 找出是否已经注册的
String registeredName = this.aliasMap.get(alias);
// 已经有人注册过这个 alias了
if (registeredName != null) {
// 那么巧、bean Name 是一样的、
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
// 是否允许 alias覆盖、默认是允许的
if (!allowAliasOverriding()) {
throw new IllegalStateException("xxx 已省略显示");
} }
// 检查是否循环依赖
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name); }
}
}

关于 alias的循环注册

protected void checkForAliasCircle(String name, String alias) {
// 我们要注册的是 name 拥有别名 alias
// 那么我们就要判断是否 有 alias 拥有别名 name 、
// 如果有的话、那么就是循环依赖了
if (hasAlias(alias, name)) {
throw new IllegalStateException("省略....");
}
}

假如我们已经有了 test拥有别名testAlias01 的关系、那么我们现在想要注册 testAlias01 拥有 别名test

这个关系、那么就检查、看看再已用的关系中是否已经有 test拥有别名testAlias01 关系、如果有则是 别名的循环依赖

A->B->C->D->A

这种也是循环

Spring 源码对应的单元测试

class SimpleAliasRegistryTests {

   @Test
void aliasChaining() {
SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("test", "testAlias");
registry.registerAlias("testAlias", "testAlias2");
registry.registerAlias("testAlias2", "testAlias3"); assertThat(registry.hasAlias("test", "testAlias")).isTrue();
assertThat(registry.hasAlias("test", "testAlias2")).isTrue();
assertThat(registry.hasAlias("test", "testAlias3")).isTrue();
assertThat(registry.canonicalName("testAlias")).isEqualTo("test");
assertThat(registry.canonicalName("testAlias2")).isEqualTo("test");
assertThat(registry.canonicalName("testAlias3")).isEqualTo("test");
} @Test // SPR-17191
void aliasChainingWithMultipleAliases() {
SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("name", "alias_a");
registry.registerAlias("name", "alias_b");
assertThat(registry.hasAlias("name", "alias_a")).isTrue();
assertThat(registry.hasAlias("name", "alias_b")).isTrue(); registry.registerAlias("real_name", "name");
assertThat(registry.hasAlias("real_name", "name")).isTrue();
assertThat(registry.hasAlias("real_name", "alias_a")).isTrue();
assertThat(registry.hasAlias("real_name", "alias_b")).isTrue(); registry.registerAlias("name", "alias_c");
assertThat(registry.hasAlias("real_name", "name")).isTrue();
assertThat(registry.hasAlias("real_name", "alias_a")).isTrue();
assertThat(registry.hasAlias("real_name", "alias_b")).isTrue();
assertThat(registry.hasAlias("real_name", "alias_c")).isTrue();
}
}

已经使用了 ConcurrentHashMap 为啥还要使用 synchronized

在注册别名时,检查别名是否注册过名称这一步,如果不对注册表加锁,会导致检查出现问题,最终导致出现重复引用

两个注册过程并发进行,在检查时两个注册过程均未发现问题,但是注册过后便会出现问题

https://blog.csdn.net/f641385712/article/details/85081323

Spring-AliasRegistry的更多相关文章

  1. 死磕Spring源码之AliasRegistry

    死磕Spring源码之AliasRegistry 父子关系 graph TD; AliasRegistry-->BeanDefinitionRegistry; 代码实现 作为bean定义的最顶层 ...

  2. Spring之28:AliasRegistry&SimpleAliasRegistry

    AliasRegistry接口定义了alias的基本操作. package org.springframework.core; public interface AliasRegistry { //对 ...

  3. Spring源码分析——BeanFactory体系之抽象类、类分析(一)

    上一篇介绍了BeanFactory体系的所有接口——Spring源码分析——BeanFactory体系之接口详细分析,本篇就接着介绍BeanFactory体系的抽象类和接口. 一.BeanFactor ...

  4. Spring源码分析——BeanFactory体系之接口详细分析

    Spring的BeanFactory的继承体系堪称经典.这是众所周知的!作为Java程序员,不能错过! 前面的博文分析了Spring的Resource资源类Resouce.今天开始分析Spring的I ...

  5. 深入剖析 Spring 框架的 BeanFactory

    说到Spring框架,人们往往大谈特谈一些似乎高逼格的东西,比如依赖注入,控制反转,面向切面等等.但是却忘记了最基本的一点,Spring的本质是一个bean工厂(beanFactory)或者说bean ...

  6. Spring源码之SimpleAliasRegistry解读(一)

    Spring源码之SimpleAliasRegistry解读(一) 阅读spring源码中org.springframework.core.SimpleAliasRegistry类时发现该类主要是使用 ...

  7. Spring MVC 解读——<context:component-scan/>

    转自:http://my.oschina.net/HeliosFly/blog/203149 作者:GoodLoser. Spring MVC 解读---<context:component-s ...

  8. spring beans源码解读之--BeanFactory的注册

    beanFactory的继承关系如下图所示: (图片来源:http://www.myexception.cn/software-architecture-design/925888.html) 在上节 ...

  9. Spring源码解析一(框架梳理)

    整体架构 打算开始写这个系列,不为上首页,也不为博取多少关注,只有一个目的:梳理知识,扩充思路:废话不多,开始吧.第一步,大家去spring的官方github下面去下载它的源码,具体的自己谷歌,我已经 ...

  10. 解析spring中的BeanFactory

    我们常把spring看作一个bean工厂或者ioc容器,它帮助我们负责对象的创建管理,以及对象间依赖关系的建立,还有其他的功能. 关于工厂的实现,一般来说与我们接触最多的就是BeanFactory和A ...

随机推荐

  1. Java实现 LeetCode 739 每日温度(暴力循环)

    739. 每日温度 根据每日 气温 列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数.如果之后都不会升高,请在该位置用 0 来代替. 例如,给定一个列表 temper ...

  2. Java实现堆排序问题(变治法)

    问题描述 用基于变治法的堆排序算法对任意一组给定的数据进行排序 2.1 堆排序原理简介 堆可以定义为一颗二叉树,树的节点中包含键(每个节点是一个键),并且满足下面两个条件: (1)树的形状要求--这颗 ...

  3. java实现第五届蓝桥杯格子放鸡蛋

    格子放鸡蛋 X星球的母鸡很聪明.它们把蛋直接下在一个 N * N 的格子中,每个格子只能容纳一枚鸡蛋.它们有个习惯,要求:每行,每列,以及每个斜线上都不能有超过2个鸡蛋.如果要满足这些要求,母鸡最多能 ...

  4. Fiddler13模拟弱网络环境测试

    前言现在的Android软件,基本上都会有网络请求,有些APP需要频繁的传输数据时对于网络请求的稳定性和在特殊网络条件下的兼容性有要求,但是我们在测试的时候又很难模拟那种弱网络差网络的情况,今天就给大 ...

  5. 温故知新-多线程-深入刨析synchronized

    Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 文章目录 摘要 synchroniz ...

  6. 智能家居巨头 Aqara 基于 KubeSphere 打造物联网微服务平台

    背景 从传统运维到容器化的 Docker Swarm 编排,从 Docker Swarm 转向 Kubernetes,然后在 Kubernetes 运行 SpringCloud 微服务全家桶,到最终拥 ...

  7. ELK的踩坑之旅

    前言 设计思路如下 有3台机器 2台做elasticsearch的主副节点 1台做kibana和elasticsearch_head 由于机器匮乏我还在这台机器上部署了logstash和nginx服务 ...

  8. Istio的运维-诊断工具(istio 系列五)

    Istio的运维-诊断工具 在参考官方文档的时候发现环境偶尔会出现问题,因此插入一章与调试有关的内容,便于简单问题的定位.涵盖官方文档的诊断工具章节 目录 Istio的运维-诊断工具 使用istioc ...

  9. Debian安装NVIDIA显卡驱动

    1. sudo apt-get install nvidia-detect nvidia-detect 输出信息: Detected NVIDIA GPUs: 01:00.0 VGA compatib ...

  10. Vue —— 精讲 VueRouter(1)

    最近被Boos调去给新人做培训去了,目前把自己整理的一些东西分享出来,希望对大家有所帮助 本章节为VueRouter前端 路由的章节部分 大纲 一.基本概念 路由就是通过网络把讯息从源地址传输到目的地 ...