SpringBean源码学习之SimpleAliasRegistry接口的hasAlias()问题

阅读spring5源码中SimpleAliasRegistry接口中遇到问题

____________________________________________________

SimpleAliasRegistry是AliasRegistry的简单实现类,其中有一个方法是hasAlias(), 用来判断"给定的名称是否已注册给定的别名",代码如下:

public class SimpleAliasRegistry implements AliasRegistry {

//从别名映射到规范名称
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

	//确定给定名称是否已注册给定别名
	public boolean hasAlias(String name, String alias) {
		String registeredName = this.aliasMap.get(alias);
		return ObjectUtils.nullSafeEquals(registeredName, name) || (registeredName != null
				&& hasAlias(name, registeredName));
	}
}
	

这里方法的返回值递归调用没看明白,于是做了简单测试

____________________________________________________

一、 原封不动,照搬原来的方法用来模拟测试

/**
 * 原封不动,照搬原来的方法用来模拟测试
 */
public class Test {
    private static Map<String,String> aliasMap=new ConcurrentHashMap<>(16);

    public static boolean hasAlias(String name, String alias) {
        String registeredName = aliasMap.get(alias);
        return ObjectUtils.nullSafeEquals(registeredName, name) || (registeredName != null
                && hasAlias(name, registeredName));
    }
	
	//测试
    public static void main(String[] args) {
    	//填充模拟数据,K为alias(别名),V为name
        aliasMap.put("z","zevin");
        aliasMap.put("zz","zevin");
        aliasMap.put("zzz","zevin");
		aliasMap.put("zevin","zzz");
		
		//判断
        System.out.println(hasAlias("zevin", "z"));
        System.out.println(hasAlias("zevin", "zz"));
        System.out.println(hasAlias("zevin", "zzz"));
        System.out.println(hasAlias("zzz", "zevin"));
    }
}
结果均为true

____________________________________________________

二、弱化hasAlias()方法,注释方法返回值上的循环调用部分,改为只调用一次就做出判断

public class Test {
    private static Map<String,String> aliasMap=new ConcurrentHashMap<>(16);

    public static boolean hasAlias(String name, String alias) {
        String registeredName = aliasMap.get(alias);
        return ObjectUtils.nullSafeEquals(registeredName, name);
    }
	
	//测试
    public static void main(String[] args) {
    	//填充模拟数据,K为alias(别名),V为name
        aliasMap.put("z","zevin");
        aliasMap.put("zz","zevin");
        aliasMap.put("zzz","zevin");
		aliasMap.put("zevin","zzz");
		
		//判断
        System.out.println(aliasMap.hasAlias("zevin","z"));
        System.out.println(aliasMap.hasAlias("zevin","zz"));
        System.out.println(aliasMap.hasAlias("zevin","zzz"));
        System.out.println(aliasMap.hasAlias("zzz","zevin"));
    }
}
结果均为true

发现:

1.ObjectUtils.nullSafeEquals(registeredName, name)该方法用来判断"别名对应注册的name和给定的name是否相等"

____________________________________________________

三、弱化hasAlias()方法,注释ObjectUtils.nullSafeEquals(registeredName, name)方法后得到

public class Test {
    private static Map<String,String> aliasMap=new ConcurrentHashMap<>(16);

    public static boolean hasAlias(String name, String alias) {
        String registeredName = aliasMap.get(alias);
        return  (registeredName != null
        		&& hasAlias(name, registeredName));
    }
	
	//测试
    public static void main(String[] args) {
    	//填充模拟数据,K为alias(别名),V为name
        aliasMap.put("z","zz");
        aliasMap.put("zz","zzz");
        aliasMap.put("zzz","zevin");
		aliasMap.put("zevin","zzz");
		
		//判断
        System.out.println(aliasMap.hasAlias("zevin","z"));
    }
}
结果报错:
Exception in thread "main" java.lang.StackOverflowError
at org.zevin.Test.hasAlias(Test.java:18)
at org.zevin.Test.hasAlias(Test.java:18)
at org.zevin.Test.hasAlias(Test.java:18)
...

发现:

1.(registeredName != null&& hasAlias(name, registeredName))这里递归调用的作用是——通过alias得到对应注册名,然后判断注册名是否存在,若存在则作为alias继续不断检索对应注册名,流程为:alias0->name0(alias1)->name1(alias2)->…
2.当存在"一个bean的beanName/alias与另一个bean的beanName/alias取反相同"时,会出现循环引用冲突,类似Bean循环依赖冲突,抛出StackOverflowError错误

____________________________________________________

三、复原代码块,继续测试

/**
 * 原来的代码
 */
public class Test {
    private static Map<String,String> aliasMap=new ConcurrentHashMap<>(16);

    public static boolean hasAlias(String name, String alias) {
        String registeredName = aliasMap.get(alias);
        return ObjectUtils.nullSafeEquals(registeredName, name) || 
        (registeredName != null&& hasAlias(name, registeredName));
    }
	
	//测试
    public static void main(String[] args) {
    	//填充模拟数据,K为alias(别名),V为name
        aliasMap.put("z","zz");
        aliasMap.put("zz","zzz");
        aliasMap.put("zzz","z");

		//判断
        System.out.println(hasAlias("z", "z"));
        System.out.println(hasAlias("z", "zz"));
        System.out.println(hasAlias("z", "zzz"));
        
        System.out.println(hasAlias("zz", "z"));
        System.out.println(hasAlias("zz", "zz"));
        System.out.println(hasAlias("zz", "zzz"));

        System.out.println(hasAlias("zzz", "z"));
        System.out.println(hasAlias("zzz", "zz"));
        System.out.println(hasAlias("zzz", "zzz"));
    }
}
结果均为true

发现:

1. ObjectUtils.nullSafeEquals(registeredName, name)用来检测——alias对应的注册BeanName和给定BeanName是否相等,即给定的beanName和给定的alias是否关联。如果返回true代表检索成功
2.(registeredName != null&& hasAlias(name, registeredName))用来循环——nullSafeEquals()没有匹配上,则继续检索下一个alias。

____________________________________________________

综上:

1、beanName可以拥有多个alias,所有alias存放在map<alias,registeredName>中。
2、通过hasAlias()方法检测"给定的名称"是否已注册"给定的别名"。
3、在map中,并不是所有alias(key)对应的value是name,需要通过递归调用,直到匹配上真正的beanName或检索失败。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值