Spring源码解析(五)-解析alias标签

Spring版本

5.2.5.RELEASE

源码解读

首先看一下alias标签的使用方式:


name属性应用对应的bean,alias属性为该bean设置别名
查阅源码:

    protected void processAliasRegistration(Element ele) {
        String name = ele.getAttribute(NAME_ATTRIBUTE);
        String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
        boolean valid = true;
        if (!StringUtils.hasText(name)) {
            getReaderContext().error("Name must not be empty", ele);
            valid = false;
        }
        if (!StringUtils.hasText(alias)) {
            getReaderContext().error("Alias must not be empty", ele);
            valid = false;
        }
        if (valid) {
            try {
                // 注册别名
                getReaderContext().getRegistry().registerAlias(name, alias);
            }
            catch (Exception ex) {
                getReaderContext().error("Failed to register alias '" + alias +
                        "' for bean with name '" + name + "'", ele, ex);
            }
            // 通知监听器别名标签解析完毕
            getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
        }
    }

该方法其实就做了俩步:

  1. 注册别名
  2. 通知监听器别名标签解析完毕

注册别名的逻辑如下:

    @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) {
            // 别名和实际名称一样,从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 {
                // 获取alias对应的已经注册的name
                String registeredName = this.aliasMap.get(alias);
                if (registeredName != null) {
                    // 如果俩者相同,所以已经注册过,直接返回
                    if (registeredName.equals(name)) {
                        // An existing alias - no need to re-register
                        return;
                    }
                    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 + "'");
                    }
                }
                // 否则,检查是否存在循环指向
                // 存在循环指向,则抛出异常
                checkForAliasCircle(name, alias);
                // 不存在循环指向,执行注册
                this.aliasMap.put(alias, name);
                if (logger.isTraceEnabled()) {
                    logger.trace("Alias definition '" + alias + "' registered for name '" + 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");
        }
    }

可以看到交由hasAlias进行处理:

    public boolean hasAlias(String name, String alias) {
        String registeredName = this.aliasMap.get(alias);
        // 如果已经注册的name(registeredName)和准备注册的name一致,那么直接返回true
        // 否则,将registeredName作为别名,继续递归hasAlias进行判断
        // 如果存在循环指向,那么必定会出现name和registeredName一致的情况
        return ObjectUtils.nullSafeEquals(registeredName, name) || (registeredName != null
                && hasAlias(name, registeredName));
    }

代码逻辑都比较清晰简单

你可能感兴趣的:(Spring源码解析(五)-解析alias标签)