Spring 源码:Alias

别名在现实世界处处存在,更有着取个英文名,什么 wiket、sophy 等,叫起来也挺顺耳的。不仅仅在姓名上取别名,连编程上都使用了,嘿,把 "wiket" 地址给我,Spring 查找了一遍,在别名模块找了指定的对象....

别名是对象标识的另一个称呼,与对象一一对应。


AliasRegistry:制定别名的管理规则:

public interface AliasRegistry {
    // 给名称注册一个别名
    void registerAlias(String name, String alias);

    // 删除一个别名
    void removeAlias(String alias);

    // 给定名称的别名是否存在
    boolean isAlias(String name);

    // 获取给定名称的别名
    String[] getAliases(String name);
}

接下来看下 AliasRegistry 实现类有哪些:

AbstractAutowireCapableBeanFactory.java
AbstractBeanFactory.java
AnnotationConfigApplicationContext.java
AnnotationConfigEmbeddedWebApplicationContext.java
BeanDefinitionRegistry.java
DefaultListableBeanFactory.java
DefaultSingletonBeanRegistry.java
EmbeddedWebApplicationContext.java
FactoryBeanRegistrySupport.java
GenericApplicationContext.java
GenericGroovyApplicationContext.java
GenericWebApplicationContext.java
GenericXmlApplicationContext.java
ResourceAdapterApplicationContext.java
SimpleAliasRegistry.java
SimpleBeanDefinitionRegistry.java
StaticApplicationContext.java
StaticWebApplicationContext.java
XmlEmbeddedWebApplicationContext.java

接下来看下如何使用:

<bean name="some" class="MDJBean.Car"/>
<alias name="some" alias="someBean"/>  
<alias name="some" alias="oneBean"/> 

一个名字可以关联多个别名。是一种一对多的关系。


接下来看 AliasRegistry 接口的基本实现类 SimpleAliasRegistry:

public class SimpleAliasRegistry implements AliasRegistry {
    protected final Log logger = LogFactory.getLog(getClass());

    //[别名-名称]的映射容器
    private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);


    @Override
    public void registerAlias(String name, String alias) {
        synchronized (this.aliasMap) {  // 同步操作
            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 define alias '" + alias + "' for name '" +
                                name + "': It is already registered for name '" + registeredName + "'.");
                    }
                }
                // alias是否已存在
                checkForAliasCircle(name, alias);
                this.aliasMap.put(alias, name);
            }
        }
    }

    /**
    * alias是否已存在,已存在则抛出IllegalStateException异常
    */
    protected void checkForAliasCircle(String name, String alias) {
        // 注意hasAlias的入参
        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");
        }
    }

    /**
    * 指定alias是否已存在
    */
    public boolean hasAlias(String name, String alias) {
        for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
            String registeredName = entry.getValue();
            /**
            * 禁止的两种情况:
            *  1、map容器(carA:car),指定(carA,car)
            *  2、map容器(carA:car,carC:carA),指定(carC,car)
            */
            if (registeredName.equals(name)) {
                String registeredAlias = entry.getKey();
                if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {
                    return true;
                }
            }
        }
        return false;
    }

    // alias是否允许被覆盖,默认为可以
    protected boolean allowAliasOverriding() {
        return true;
    }

    // 移除别名
    @Override
    public void removeAlias(String alias) {
        synchronized (this.aliasMap) {
            String name = this.aliasMap.remove(alias);  //移除动作
            if (name == null) {  // 被移除的alias不存在则抛出异常
                throw new IllegalStateException("No alias '" + alias + "' registered");
            }
        }
    }

    /**
    * 重构容器
    */ 
    public void resolveAliases(StringValueResolver valueResolver) {
        synchronized (this.aliasMap) {  // 同步
            Map<String, String> aliasCopy = new HashMap<>(this.aliasMap);
            aliasCopy.forEach((alias, registeredName) -> { 
                //别名、名称变换动作
                String resolvedAlias = valueResolver.resolveStringValue(alias);
                String resolvedName = valueResolver.resolveStringValue(registeredName);
                // 变换后alias || name为null || alias和name一样,则移除
                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) { // 对应别名存在,移除或抛出异常
                        // 容器中已存在变换后的alias
                        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 + "'.");
                    }
                    // 容器中不存在变换后的alias,
                    checkForAliasCircle(resolvedName, resolvedAlias);
                    // 移除旧的alias
                    this.aliasMap.remove(alias);
                    // 添加变换后的alisa-name对
                    this.aliasMap.put(resolvedAlias, resolvedName);
                }
                else if (!registeredName.equals(resolvedName)) {
                    this.aliasMap.put(alias, resolvedName);
                }
            });
        }
    }

    /**
     * 获取原始名称,如果传进来是别名的则获取对应的名称
     * 
     * 这里使用do-while情况:[A->B B->C] => [(A and B)->C]
     * 查找过程:通过A找到B,再通过B找到C
     */
    public String canonicalName(String name) {
        String canonicalName = name;
        String resolvedName;
        do {
            resolvedName = this.aliasMap.get(canonicalName);
            if (resolvedName != null) {
                canonicalName = resolvedName;
            }
        }
        while (resolvedName != null);
        return canonicalName;
    }

}

在验证别名正确性的流程中,不允许出现环路:

<bean name="B" class="MDJBean.Car"/>
<bean name="C" class="MDJBean.Car"/>
<alias name="B" alias="A"/>   // A->B 
<alias name="C" alias="B"/>   // B->C  
==> (A & B)->C


<bean name="B" class="MDJBean.Car"/>
<bean name="A" class="MDJBean.Car"/>
<alias name="B" alias="A"/>   // A->B 
<alias name="A" alias="C"/>   // C->A  
==> (A & C->B)

如上图,如果 (A & B) ->C,定义一个 C->A 的关系,这时候出现环路,这是不允许出现的情况,直接抛出异常。

所以 hasAlias() 方法则是查找待设置的别名关系是否会导致环路出现,如下所示:


思考:

  • 通过 alias 可以获取指定 bean 的实例,它是获取 bean 实例的另一种方式;
  • 别名和名称不能一样,一样则被移除。名字叫张三的童孩,别名也是张三,这样别名就没有任何意义了;
  • 可以对指定的 bean 创建多个 alias,bean 与 alias 是一对多的关系;
  • bean 之间不允许环路 alias,即 A - > B,B - > C,C - > A;
  • 针对(A->B B->C) => (A & B->C)在哪一步做处理了?
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值