别名的注册
SimpleAliasRegistry维护了一个映射别名到真实名称的aliasMap这里使用的是线程安全的ConcurrentHashMap,即在多线程的情况下也可以对同一个bean安全地进行别名的增删改查。同时也说明了一个别名只能对应一个真名,而一个真名没有对应多个别名。由于SimpleAliasRegistry是对项目全局别名的管理,任意别名都必须是全局唯一的。
别名的注册主要用到了方法registerAlias,调用了checkForAliasCircle用于检查别名和真名是否造成了循环。这说明了bean的所有别名、真名之间都不可以出现循环注册。
// 映射别名到真实名称的关系
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
// 用于注册别名
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)) {
// 如果要注册的别名是和真实名称相同,则说明不需要这个别名,在aliasMap中可以移除这个别名对应的项
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
}
else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
//别名已经被注册
if (registeredName.equals(name)) {
//如果和输入的真名相同,则说明已存在该别名和真名的映射,不需要重复注册
return;
}
//别名已被其它真名注册,发生overriding
if (!allowAliasOverriding()) {
// 如果不允许overriding,则抛出异常。默认allowAliasOverriding为true(允许)
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isDebugEnabled()) {
// 可以override别名,增加日志信息,说明该别名对应的真名被覆盖重写了
logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
// 检查是否造成循环,向aliasMap中插入这个对应关系
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
// 确保不存在从name到alias的映射
protected void checkForAliasCircle(String name, String alias) {
if (hasAlias(alias, name)) {
throw new IllegalStateException("Cannot register alias '" + alias +
"' for name '" + name + "': Circular reference - '" +
name + "' is a direct or indirect alias for '" + alias + "' already");
}
}
// 例如name = A,alias = a,aliasMap中有(a, A)或者aliasMap中有(a, x)和(x, A),则说明存在从别名a到真名A的映射
public boolean hasAlias(String name, String alias) {
String registeredName = (String)this.aliasMap.get(alias);
return ObjectUtils.nullSafeEquals(registeredName, name) || registeredName != null && this.hasAlias(name, registeredName);
}
别名的获取
// 返回一个真名对应的所有别名
public String[] getAliases(String name) {
List<String> result = new ArrayList<>();
synchronized (this.aliasMap) {
retrieveAliases(name, result);
}
return StringUtils.toStringArray(result);
}
// 获取一个真实name对应的所有别名,在aliasMap中逐个对value进行比较,注意这是一个内部方法,外部调用统一使用的是registerAlias
private void retrieveAliases(String name, List<String> result) {
this.aliasMap.forEach((alias, registeredName) -> {
if (registeredName.equals(name)) {
result.add(alias);
retrieveAliases(alias, result);
}
});
}
获取别名对应的真实名称
当aliasMap中的key中不存在name时,说明这个name没有被注册为别名,则说明它对应的真名就是自己。如果被注册为别名了,则循环不断找到最后的真名。如aliasMap中有(a, b), (b, c)就说明name = a时返回的最终真名是c,这里的b可以视为一个间接别名。
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
resolvedName = (String)this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
// 因为插入时确保了没有循环映射,所以这个循环总是可以跳出的
} while(resolvedName != null);
return canonicalName;
}