Spring源码阅读之DefaultListableBeanFactory系列-SimpleAliasRegistry

SimpleAliasRegistry是AliasRegistry的具体实现,具体实现了对别名的增删改等操作。

相关源码分析:

/**
 * 实现对别名的增删改等操作
 */
public class SimpleAliasRegistry implements AliasRegistry {

    /**
     * 别名缓存,key是别名,value是name,在这里用ConcurrentHashMap是为了保证对别名的操作线程安全
     */
    private final Map<String, String> aliasMap = new ConcurrentHashMap<String, String>(16);

    /**
     * 给该name的bean定义一个别名
     * @param name bean的name
     * @param 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");
        if (alias.equals(name)) {
            this.aliasMap.remove(alias);
        }
        else {
            String registeredName = this.aliasMap.get(alias);
            if (registeredName != null) {
                if (registeredName.equals(name)) {
                    // 别名已经存在,不需要再注册
                    return;
                }
                //别名已存在并且不允许被覆盖
                if (!allowAliasOverriding()) {
                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                            name + "': It is already registered for name '" + registeredName + "'.");
                }
            }
            //判断此别名是否已经存在
            checkForAliasCircle(name, alias);
            //将name的别名写入缓存
            this.aliasMap.put(alias, name);
        }
    }

    /**
     * 是否允许别名被覆盖
     * @return
     */
    protected boolean allowAliasOverriding() {
        return true;
    }

    /**
     * 判断该name的bean是否有此别名
     * @param name
     * @param alias
     * @return
     */
    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();
                /*
                假如是我,我可能会这么写,我觉得这样写法就时间复杂度来说是优于下面的写法的,我猜测那么写可能是为了优雅吧
                if (registeredAlias.equals(alias)) {
                    return true;
                }
                 */
                return (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias));
            }
        }
        return false;
    }

    /**
     * 移除制定的别名
     * @param alias 需要移除的别名
     */
    @Override
    public void removeAlias(String alias) {
        String name = this.aliasMap.remove(alias);
        if (name == null) {
            throw new IllegalStateException("No alias '" + alias + "' registered");
        }
    }

    /**
     * 判断name是否是已经注册的别名
     * @param name
     * @return
     */
    @Override
    public boolean isAlias(String name) {
        return this.aliasMap.containsKey(name);
    }

    /**
     * 返回该name注册的所有的别名
     * @param name
     * @return
     */
    @Override
    public String[] getAliases(String name) {
        List<String> result = new ArrayList<String>();
        synchronized (this.aliasMap) {
            retrieveAliases(name, result);
        }
        return StringUtils.toStringArray(result);
    }

    /**
     * 获取该name的所有的别名
     * @param name
     * @param result
     */
    private void retrieveAliases(String name, List<String> result) {
        for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
            String registeredName = entry.getValue();
            if (registeredName.equals(name)) {
                String alias = entry.getKey();
                result.add(alias);
                /**
                 * 同样的,我觉得没有必要再在这里递归
                 */
                retrieveAliases(alias, result);
            }
        }
    }

    /**
     * 将valueResolver所带的alias和name写入缓存
     * @param valueResolver
     */
    public void resolveAliases(StringValueResolver valueResolver) {
        //参数校验
        Assert.notNull(valueResolver, "StringValueResolver must not be null");
        //加锁,保证线程安全,不明白的是CurrentHashMap已经线程安全了,为什么还需要加锁排队呢
        synchronized (this.aliasMap) {
            Map<String, String> aliasCopy = new HashMap<String, String>(this.aliasMap);
            for (String alias : aliasCopy.keySet()) {
                String registeredName = aliasCopy.get(alias);
                String resolvedAlias = valueResolver.resolveStringValue(alias);
                String resolvedName = valueResolver.resolveStringValue(registeredName);
                if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) {
                    this.aliasMap.remove(alias);
                }
                else if (!resolvedAlias.equals(alias)) {
                    String existingName = this.aliasMap.get(resolvedAlias);
                    if (existingName != null) {
                        if (existingName.equals(resolvedName)) {
                            // Pointing to existing alias - just remove placeholder
                            this.aliasMap.remove(alias);
                            break;
                        }
                        throw new IllegalStateException(
                                "Cannot register resolved alias '" + resolvedAlias + "' (original: '" + alias +
                                        "') for name '" + resolvedName + "': It is already registered for name '" +
                                        registeredName + "'.");
                    }
                    checkForAliasCircle(resolvedName, resolvedAlias);
                    this.aliasMap.remove(alias);
                    this.aliasMap.put(resolvedAlias, resolvedName);
                }
                else if (!registeredName.equals(resolvedName)) {
                    this.aliasMap.put(alias, resolvedName);
                }
            }
        }
    }

    /**
     * 判断name的该别名是否存在
     * @param name
     * @param 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");
        }
    }

    /**
     * Determine the raw name, resolving aliases to canonical names.
     * @param name
     * @return
     */
    public String canonicalName(String name) {
        String canonicalName = name;
        // Handle aliasing...
        String resolvedName;
        do {
            resolvedName = this.aliasMap.get(canonicalName);
            if (resolvedName != null) {
                canonicalName = resolvedName;
            }
        }
        while (resolvedName != null);
        return canonicalName;
    }
}
详细的注释已经在上述的源码中被给出,再次我不再对源码做详细的赘述。

说说我看这段源码心里的疑问吧:

  • 缓存的数据结构是CurrentHashMap,已经线程安全了,为什么还需要用synchronized关键字来再一次保证线程安全,这样会降低处理的效率的;
  • 递归的相关使用,是为了保证代码优雅么?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值