Spring源码分析之AliasRegistry(2)
上一篇博客介绍了别名在spring中的简单使用,这篇来看一下AliasRegistry的具体实现。
别名管理器的具体实现
public interface AliasRegistry {
/**
* 对一个name注册别名
*/
void registerAlias(String name, String alias);
/**
* 移除一个别名
*/
void removeAlias(String alias);
/**
* 检查一个name是否为别名
*/
boolean isAlias(String name);
/**
* 获取一个name的所有别名
*/
String[] getAliases(String name);
}
这是spring中对AliasRegistry的定义,方法都是很明确的,接下来我们一个一个来解析。
AliasRegistry在spring中只有一个直接实现类SimpleAliasRegistry。先看一下SimpleAliasRegistry的简单使用,
public class Client {
public static void main(String[] args) {
AliasRegistry aliasRegistry = new SimpleAliasRegistry();
aliasRegistry.registerAlias("userService", "userService1");
aliasRegistry.registerAlias("userService", "userService2");
System.out.println("userService的别名为 " + Arrays.toString(aliasRegistry.getAliases("userService")));
System.out.println("userService1是否为别名:" + aliasRegistry.isAlias("userService1"));
aliasRegistry.removeAlias("userService1");
System.out.println("userService的别名为 " + Arrays.toString(aliasRegistry.getAliases("userService")));
System.out.println("userService1是否为别名:" + aliasRegistry.isAlias("userService1"));
}
}
对userService注册两个别名userService1,userService2,输出结果为
userService的别名为 [userService2, userService1]
userService1是否为别名:true
userService的别名为 [userService2]
userService1是否为别名:false
结果符合预期,接下来看一下源码实现。
public class SimpleAliasRegistry implements AliasRegistry {
/**
* 内部使用一个ConcurrentHashMap来存储,保证线程安全
*/
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)) {
// 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 + "'.");
}
}
//检查是否有别名的循环如A->B B->C C->A就是一个循环
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}
}
/**
* 是否允许将别名挂到别的本名上,默认允许
*/
protected boolean allowAliasOverriding() {
return true;
}
/**
* 检查一个本名是否有指定别名,别名是可以递归注册的,如A->B B->C 那么C也是A的别名
*/
public boolean hasAlias(String name, String alias) {
for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
String registeredName = entry.getValue();
if (registeredName.equals(name)) {
String registeredAlias = entry.getKey();
if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {
return true;
}
}
}
return false;
}
/**
* 删除一个别名
*/
@Override
public void removeAlias(String alias) {
synchronized (this.aliasMap) {
String name = this.aliasMap.remove(alias);
if (name == null) {
throw new IllegalStateException("No alias '" + alias + "' registered");
}
}
}
@Override
public boolean isAlias(String name) {
return this.aliasMap.containsKey(name);
}
@Override
public String[] getAliases(String name) {
List<String> result = new ArrayList<>();
synchronized (this.aliasMap) {
retrieveAliases(name, result);
}
return StringUtils.toStringArray(result);
}
/**
* 递归的查找出一个本名的所有别名
*/
private void retrieveAliases(String name, List<String> result) {
this.aliasMap.forEach((alias, registeredName) -> {
if (registeredName.equals(name)) {
result.add(alias);
retrieveAliases(alias, result);
}
});
}
/**
* 使用字符串解析器如占位符解析器解析所有别名
*/
public void resolveAliases(StringValueResolver valueResolver) {
Assert.notNull(valueResolver, "StringValueResolver must not be null");
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);
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) {
if (existingName.equals(resolvedName)) {
// Pointing to existing alias - just remove placeholder
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 + "'.");
}
checkForAliasCircle(resolvedName, resolvedAlias);
this.aliasMap.remove(alias);
this.aliasMap.put(resolvedAlias, resolvedName);
}
else if (!registeredName.equals(resolvedName)) {
this.aliasMap.put(alias, resolvedName);
}
});
}
}
/**
* 检查是否存在别名的环
*/
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");
}
}
/**
* 根据一个别名获取到本名
*/
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
}
别名的存储方式为
别名->本名,允许递归注册别名,如A的别名为B,B的别名为C,那么C也是A的别名,如果C的别名是A,那么就会存在环的问题。