DefaultListBeanFactory的子类之SimpleAliasRegistry


DefaultListBeanFactory类结构层次图

ClassHierarchy

从继承图看,SimpleAliasRegistry是DefaultListBeanFactory继承类中最底层的实现类。

SimpleAliasRegistry

SimpleAliasRegistry

GitHub:
SimpleAliasRegistry.java
SimpleAliasRegistryTests.java

SimpleAliasRegistry借助ConcurrentHashMap来做别名的存储,用KEY 存储别名alias,用VALUE 存储别名对应的真名或者别名

1.registerAlias(String name, String 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");
        synchronized (this.aliasMap) {
            if (alias.equals(name)) {
                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)) {
                        // 已经存在的别名 - 不需要再次注册,Map中已经有alias->registeredName了且registeredName等于name
                        return;
                    }
                    // 比方说Map中有alias->registeredName了
                    // 你现在却要求改为alias->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 + "'");
                    }
                }
                // 如果说Map中已经存在name->alias,
                // 那么现在alias->name就是循环引用了
                // 会抛出异常
                checkForAliasCircle(name, alias);
                this.aliasMap.put(alias, name);
                if (logger.isTraceEnabled()) {
                    logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
                }
            }
        }
    }

checkForAliasCircle(String name, String alias)

检查是不是已经存在name->alias,却还要注册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");
    }
}

2.hasAlias(String name, String alias)

虽然这 是接口AliasRegistry的方法,但确是SimpleAliasRegister判断name是否包含别名alias的重要方法。采取的方法是先找Map的Value(即先找name),找到name之后可以判断该name对应的registeredAlias是否和参数中的alias相同,如果相同返回true,不相同则递归寻找。

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) || hasAlias(registeredAlias, alias))              {
                return true;
            }
        }
    }
    return false;
}

hasAlias方法实现了链式查找别名

SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("test", "testAlias");
registry.registerAlias("testAlias", "testAlias2");
registry.registerAlias("testAlias2", "testAlias3");

我们可以得到(别名alias,原名name)的对应Map
testAlias->test
testAlias2->testAlias
testAlias3->testAlias2
那么我们就testAlias3->testAlias2->testAlias->test,使用hasAlias寻找的方向与箭头方法相反

再比如


SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("name", "alias_a");
registry.registerAlias("name", "alias_b");

registry.registerAlias("real_name", "name");

registry.registerAlias("name", "alias_c");
}

alias_abc

这里的每一条连接线+连接线首位两个实体=concurrentHashMap中的一条记录。总共三条别名链,他们分别是
alias_a->name->real_name;
alias_b->name->real_name;
alias_c->name->real_name;
位于链尾的real_name的就是canonicalName

3.canonicalName(String name)

输入一个name参数(可能是别名alias),查询他的规范名,也就是位于链尾的name

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;
}

4. getAlias(String name)

public String[] getAliases(String name) {
    List<String> result = new ArrayList<>();
    synchronized (this.aliasMap) {
        retrieveAliases(name, result);
    }
    return StringUtils.toStringArray(result);
}
private void retrieveAliases(String name, List<String> result) {
    this.aliasMap.forEach((alias, registeredName) -> {
        if (registeredName.equals(name)) {
            result.add(alias);
            retrieveAliases(alias, result);
        }
    });
}

lambda 表达式不好懂,咱们再翻译一下

private void retrieveAliases(String name, List<String> result) {
    for (Map.Entry<String, String> entry : aliasMap.entrySet()) {
        String alias = entry.getKey();
        String registeredName = entry.getValue();
        if (registeredName.equals(name)) {
            result.add(alias);
            retrieveAliases(alias, result);
        }
    });
}

从Map中先找匹配的value(name),找到了,就把对应key(alias)添加到列表中,再把key(alias)当成name,继续寻找。举个例子,如果有这样一条别名链
a->b->c->d,那么
getAlias("d") 结果是["c", "b" ,"a"]
getAlias("c") 结果是["b" ,"a"]
getAlias("b") 结果是["a"]
getAlias("a") 结果是[]

5.resolveAliases(StringValueResolver valueResolver

这个方法和registerAlias(String name, String alias)相似度极高。
在执行resolveAliases之前,aliasMap中存储的是(别名alias,别名目标名称registeredName),运用值解析器解析之后,别名alias将被替换为resolvedAlias,

/**
 * 解析在此工厂中注册的所有别名目标名称和别名,并将给定的
 * StringValueResolver应用于它们。
 * 例如,值解析器可以解析目标bean名称中的占位符,甚至可以
 * 解析别名中的占位符。
 */
public void resolveAliases(StringValueResolver valueResolver) {
    Assert.notNull(valueResolver, "StringValueResolver must not be null");
    synchronized (this.aliasMap) {
        // 拷贝一份aliasMap,这样就可以再遍历aliasMap副本时,修改原aliasMap
        Map<String, String> aliasCopy = new HashMap<>(this.aliasMap);
        aliasCopy.forEach((alias, registeredName) -> {
            // 
            String resolvedAlias = valueResolver.resolveStringValue(alias);
            String resolvedName = valueResolver.resolveStringValue(registeredName);
            // (情况零)
            // 如果解析出的别名或者解析出的目标名称为null,亦或者两者相同,则移除alias->registeredName
            if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) {
                this.aliasMap.remove(alias);
            }
            else if (!resolvedAlias.equals(alias)) {
                // 如果已解析的别名resolvedAlias不等于alias
                String existingName = this.aliasMap.get(resolvedAlias);
                if (existingName != null) {
                    if (existingName.equals(resolvedName)) {
                        // (情况二)
                        // 指向现有别名,只需要删除占位符
                        this.aliasMap.remove(alias);
                        return;
                    }
                    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)) {
                // (情况三)
                // 如果已解析的别名resolvedAlias等于alias
                // 但是已解析的注册名resolvedName不等于原注册名registeredName
                // 则使用已解析的注册名resolvedName覆盖原注册名registeredName
                // alias->resolvedName
                this.aliasMap.put(alias, resolvedName);
            }
        });
    }
}

情况一

  • 假如alias不等于resolvedAlias,且resolvedAlias->existingName不存在。那么,移除alias->resigteredName,新增resolvedAlias->resolvedName
    情况一

情况二

  • 假如alias不等于resolvedAlias,且resolvedAlias->existingName已经存在,那么移除alias->resigteredName
    情况二

情况三

  • 假如alias等于resolvedAlias,且resolvedName不等于registeredName。那么,用resolvedAlias/alias->resolvedName覆盖alias->resigteredName

  • StringValueResolver的结构图:
    StringValueResolver

  • StringValueResolver的主要接口方法
    String resolveStringValue(String strVal),其作用是解析给定的String值,例如解析占位符


作者:贼宇,发布于:2019/07/11
原文:https://www.cnblogs.com/zaid/p/11167579.html