zoukankan      html  css  js  c++  java
  • 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,那么就会存在环的问题。

  • 相关阅读:
    python json 和 pickle的补充 hashlib configparser logging
    go 流程语句 if goto for swich
    go array slice map make new操作
    go 基础
    块级元素 行内元素 空元素
    咽炎就医用药(慢性肥厚性咽炎)
    春季感冒是风寒还是风热(转的文章)
    秋季感冒 咳嗽 怎么选药
    解决IE浏览器“无法显示此网页”的问题
    常用的 css 样式 记录
  • 原文地址:https://www.cnblogs.com/strongmore/p/13798738.html
Copyright © 2011-2022 走看看