• 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,那么就会存在环的问题。

  • 相关阅读:
    css样式2 布局 定位 层级 显示
    css与样式
    表单属性、键值对
    表单
    列表、表格
    实体、颜色、路径、标签、超链接、图片
    2018/07/05 html基础
    TP 链接数据库与Model模型的创建
    ThinkPHP 模板循环语法
    tp 单字母函数详解(摘自网络)
  • 原文地址:https://www.cnblogs.com/strongmore/p/13798738.html
Copyright © 2020-2023  润新知