org.springframework.core.SimpleAliasRegistry.java 是一个关于spring注册别名的java类
重要变量:
/** Map from alias to canonical name */ private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
方法解读:
首先从注册方法入手:
@Override public void registerAlias(String name, String alias)
注册考虑并发情况,增加同步锁
synchronized (this.aliasMap)
alias和name必须不相同才会注册进aliasMap,否则不成功
if (alias.equals(name)) { this.aliasMap.remove(alias);
当name与当前alias的别名注册过的name不相同时,默认不允许覆盖,并抛出异常
if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); }
这里存在一个方法去防止注册循环,之后重点学习下
checkForAliasCircle(name, alias);
通过循环注册验证后,完成注册
this.aliasMap.put(alias, name);
现在看一下
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"); } }
如何处理循环别名引用
public boolean hasAlias(String name, String alias) { for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) { String registeredName = entry.getValue(); if (registeredName.equals(name)) { String registeredAlias = entry.getKey(); return (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)); } } return false; }
通过真实name确定是否存在alias,并判断registedAlias是否等于等待注册的alias,如果是,则返回true;如果相等,递归循环判断是否存在真名a的别名为b,b的别名为c,如果最初的参数为(a,c)这样环形引用的情况返回的是true.猜测:也就是说,在获取别名时,b和c都是a的alias,那么使用b和c作为别名,都可以获得相同的真名!验证:
public String canonicalName(String name)
do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null);
这里的循环判断正是处理这种循环引用的,以达到别名的别名也可以引用canonicalName.
获取alias,因为可能存在读写冲突,所以在筛选alias结果集的时候,需要同步
public String[] getAliases(String name)
synchronized (this.aliasMap) { retrieveAliases(name, result); }
this.aliasMap.forEach((alias, registeredName) -> { if (registeredName.equals(name)) { result.add(alias); retrieveAliases(alias, result); } });
这里也是处理循环引用的方式,通过canonicalName可以获取所有别名包括别名的别名.
之后还有一个方法:
public void resolveAliases(StringValueResolver valueResolver)
这个方法主要存储格式化处理后的name和alias