杀死Spring - BeanFactory系列中的bean别名alias机制
Spring主要是通过SimpleAliasRegistry来完成别名功能的,它的类图继承关系如下:
那么它是怎么完成的呢?
一:域
/*存储别名
*若jdk >=1.5,返回java.util.concurrent.ConcurrentHashMap,否则
*加载并返回edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap,否则
*返回SynchronizedMap
*存的内容是 别名 -> bean名,为什么这样存呢?因为一个bean可以有很多别名
*/
private final Map aliasMap = CollectionFactory.createConcurrentMapIfPossible(16);
二:方法
2.1:registerAlias
//注册别名
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
//若别名和bean名一样则删除
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
//否则加入 别名 —> bean名
else {
if (!this.allowAliasOverriding()) {
String registeredName = (String)this.aliasMap.get(alias);
if (registeredName != null && !registeredName.equals(name)) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
}
}
this.aliasMap.put(alias, name);
}
}
protected boolean allowAliasOverriding() { return true; }
2.2:getAliases
//获取某个bean名的别名
public String[] getAliases(String name) {
List aliases = new ArrayList();
//获取aliasMap的锁
synchronized(this.aliasMap) {
Iterator it = this.aliasMap.entrySet().iterator();
//遍历aliasMap,若bean名(value)跟name相等则将别名(key)加入aliases
while(it.hasNext()) {
Entry entry = (Entry)it.next();
String registeredName = (String)entry.getValue();
if (registeredName.equals(name)) {
aliases.add(entry.getKey());
}
}
//返回aliases的数组形式
return StringUtils.toStringArray(aliases);
}
}
2.3:isAlias
//aliasMap中key值集合是否有name
public boolean isAlias(String name) { return this.aliasMap.containsKey(name); }
2.4:canonicalName
//简单名字canonical:最简单,经典的,规范的
//若aliasMap中存了 a->b,b->c,c->d返回的就是d
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName = null;
//我怎么感觉下面这个循环有毛病啊,要是aliasMap中存了 a->b,b->a那不死循环了
do {
resolvedName = (String)this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
} while(resolvedName != null);
return canonicalName;
}
2.5:resolveAliases
//
public void resolveAliases(StringValueResolver valueResolver) {
Assert.notNull(valueResolver, "StringValueResolver must not be null");
//获取aliasMap的锁
synchronized(this.aliasMap) {
Map aliasCopy = new HashMap(this.aliasMap);
Iterator it = aliasCopy.keySet().iterator();
//复制一份aliasMap然后遍历它的key
while(it.hasNext()) {
//别名
String alias = (String)it.next();
//当前别名对应的bean名
String registeredName = (String)aliasCopy.get(alias);
//替换别名中的占位符
String resolvedAlias = valueResolver.resolveStringValue(alias);
//替换bean名中的占位符
String resolvedName = valueResolver.resolveStringValue(registeredName);
//如果替换占位符后的别名和别名不相等
if (!resolvedAlias.equals(alias)) {
//替换占位符后的别名对应的bean名和替换占位符后bean名不同就抛异常
String existingName = (String)this.aliasMap.get(resolvedAlias);
if (existingName != null && !existingName.equals(resolvedName)) {
throw new IllegalStateException("Cannot register resolved alias '" + resolvedAlias + "' (original: '" + alias + "') for name '" + resolvedName + "': It is already registered for name '" + registeredName + "'.");
}
//存入替换占位符后别名 -> 替换占位符后的bean名
this.aliasMap.put(resolvedAlias, resolvedName);
//删除未替换占位符别名
this.aliasMap.remove(alias);
}
//如果替换占位符后的bean名和没替换后的bean名不相等
else if (!registeredName.equals(resolvedName)) {
//存入未替换占位符的别名 -> 替换占位符的bean名
this.aliasMap.put(alias, resolvedName);
}
}
}
}
三:总结
3.1在调用resolveAliases方法之前aliasMap中存的还是带有占位符的数据,而且占位符所对应的值在PlaceholderResolvingStringValuesResolver类的props中,这个变量的值是通过其构造方法赋予的,那么在获得其值我们还需要知道spring在启动时是怎么new PlaceholderResolvingStringValuesResolver的,也就是怎么将${}对应的值注入到props中的,这个请参考
3.2