public interface AliasRegistry { /** * Given a name, register an alias for it. * @param name the canonical name * @param alias the alias to be registered * @throws IllegalStateException if the alias is already in use * and may not be overridden */ void registerAlias(String name, String alias); 为你的xml中的声明的bean id 注册 别名 /** * Remove the specified alias from this registry. * @param alias the alias to remove * @throws IllegalStateException if no such alias was found */ void removeAlias(String alias); 移除别名 /** * Determine whether this given name is defines as an alias * (as opposed to the name of an actually registered component). * @param name the name to check * @return whether the given name is an alias */ boolean isAlias(String name); 判断是否存在此别名 /** * Return the aliases for the given name, if defined. * @param name the name to check for aliases * @return the aliases, or an empty array if none */ String[] getAliases(String name); 获取所有别名 }
我们来看一下它的一个实现类
public class SimpleAliasRegistry implements AliasRegistry { /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); /** Map from alias to canonical name. */ private final MapaliasMap = new ConcurrentHashMap<>(16); 定义一个存储 别名---->bean id 的map //注册别名 @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)) { 如果 别名 和 bean id 一样 移除 作为key的 别名 就算不存在也不会抛异常 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); 从别名的map中获取 bean id if (registeredName != null) { //如果真实存在 if (registeredName.equals(name)) { //但是已经注册过了 // An existing alias - no need to re-register return; 结束程序 } if (!allowAliasOverriding()) { //是否允许别名复写 默认为true 否则抛异常 说 这个别名已经被注册了 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 + "'"); } } checkForAliasCircle(name, alias);// 检查bean id 和 别名 是否 别名陷入循环 往下看哦 this.aliasMap.put(alias, name); //添加 新的 别名 bean id 的映射关系 if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } } /** * Return whether alias overriding is allowed. * Default is {@code true}. */ protected boolean allowAliasOverriding() { return true; } /** * Determine whether the given name has the given alias registered. * @param name the name to check * @param alias the alias to look for * @since 4.2.1 */ public boolean hasAlias(String name, String alias) { for (Map.Entry entry : this.aliasMap.entrySet()) { String registeredName = entry.getValue(); // 获取bean id if (registeredName.equals(name)) { 如果此时bean id 和形参 name 相同 String registeredAlias = entry.getKey(); //获取 别名 if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) { return true; //如果 别名 和 alias 相同的时候 说明 name 有别名 即 alias //如果 别名 和 alias 第一次不相同的时候 把 别名 作为 bean id , alias作为 别名 重新传到 hasAlias 方法中 如果 registeredName.equals(name) 等于 true 说明 有别名 否则继续找 直到找不到 返回 false. eg: 1、 name = "Y" alias = "Q" 2、 name = "X" alias = "N" 3、 name="C" alias = "B" 这种的直接找不到 返回false 第二种情况 X 的 别名有两个 一个是 U 另一个是N 我是对应两种情况说的 不明白的多看一下 很简单的,加油 } } } return false; } @Override public void removeAlias(String alias) { synchronized (this.aliasMap) { String name = this.aliasMap.remove(alias); //移除别名和bean id 的映射 如果不存在的话 抛出异常 if (name == null) { throw new IllegalStateException("No alias '" + alias + "' registered"); } } } @Override public boolean isAlias(String name) { return this.aliasMap.containsKey(name); name 作为别名 是否存在 在aliasMap中 } @Override public String[] getAliases(String name) { List result = new ArrayList<>(); synchronized (this.aliasMap) { retrieveAliases(name, result); //查询name 的别名 上面已经说了 一个bean id 可以有 多个别名 所以是数组 请看上面例子 retrieveAliases 解析 方法往下看 } return StringUtils.toStringArray(result); } /** * Transitively retrieve all aliases for the given name. * @param name the target name to find aliases for * @param result the resulting aliases list */ private void retrieveAliases(String name, List result) { this.aliasMap.forEach((alias, registeredName) -> { if (registeredName.equals(name)) { //循环 aliasMap 如果bean id 包含 name 就往List 中 加入 别名 result.add(alias); retrieveAliases(alias, result); //因为一个bean id 可能有多个别名 而且别名可能 是另一个bean id 所以在查 如果有 继续往List 中 加入 别名 直到 别名 作为bean id 这个条件不成立 然后 返回 List } }); } /** * Resolve all alias target names and aliases registered in this * factory, applying the given StringValueResolver to them. * The value resolver may for example resolve placeholders * in target bean names and even in alias names. * @param valueResolver the StringValueResolver to apply */ public void resolveAliases(StringValueResolver valueResolver) { Assert.notNull(valueResolver, "StringValueResolver must not be null"); synchronized (this.aliasMap) { Map
aliasCopy = new HashMap<>(this.aliasMap); 新建一个跟aliasMap内容一样的Map aliasCopy.forEach((alias, registeredName) -> { String resolvedAlias = valueResolver.resolveStringValue(alias); //去除 可能存在的${} 符号 String resolvedName = valueResolver.resolveStringValue(registeredName);//去除 可能存在的${} 符号 if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) { this.aliasMap.remove(alias); 如果 resolvedAlias是null 或者 resolvedName是null 或者二者相同 移除alias } else if (!resolvedAlias.equals(alias)) { 如果存在 ${} 符号 而且 resolvedAlias 才是最后的内容 String existingName = this.aliasMap.get(resolvedAlias); //获取 resolvedAlias 对应的 bean id if (existingName != null) { if (existingName.equals(resolvedName)) { //如果 bean id 相同 就是 一个bean id 对应两个key eg: 删除 那个 带有 ${}符号的 映射关系 最后只会剩下 这种情况 // Pointing to existing alias - just remove placeholder this.aliasMap.remove(alias); return; } // 如果不一样 抛出异常 这块着实不太理解 不知道怎么翻译 大概意思应该是 resolvedAlias 对应的bean id 即 existingName不等于 resolvedName的时候 抛出 不能注册 resolvedAlias 来源于 alias 作为 resolvedName的别名 它已经被 registeredName注册了 应该是 resolvedName 和 registeredName 不相同 不允许 同时带有${}的key value 键值对和 key value 共存 eg: ${xxx} -> ${yyyy} xxx->yyyy 只留下 xxx->yyyy 这种 键值对 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); 就再存一个映射关系 这块已不是很理解 可能需要大佬 解决一下 } }); } } /** * Check whether the given name points back to the given alias as an alias * in the other direction already, catching a circular reference upfront * and throwing a corresponding IllegalStateException. * @param name the candidate name * @param alias the candidate alias * @see #registerAlias * @see #hasAlias */ 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 the user-specified name * @return the transformed name */ //这个方法 找到 一个不会充当 别名的bean id 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; } }
综上吧 这个代码虽然很短 但是想要理解逻辑需要自己写测试类 运行哦 一定从最小的部分下手 不然的话 你会吃大亏的 逻辑千千万 说实话 我很矛盾 真是又爱又恨 每次看spring源代码都是一知半解 不过今天写了一下 感觉不错哦 看是没用的 需要动手啊 加油
估计没人转载我的文章吧 要是觉得还行呢 就附上链接吧