阅读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) {
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) {
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) {
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) {
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或检索失败。