【源码】Spring —— AliasRegistry BeanDefinitionRegistry 解读

217 阅读3分钟

【源码】Spring —— AliasRegistry BeanDefinitionRegistry 解读

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

AliasRegistry 别名管理的顶层接口,BeanDefinitionRegistryAliasRegistry 下一个核心的分支,抽象了 BeanDefinition 的注册相关操作

版本

Spring 5.2.x

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);

}

顶层接口,定义了别名管理的相关方法

SimpleAliasRegistry

AliasRegistry 的简单实现,基于 Map 管理别名(key 为别名,name 为原名),别名的注册可以 传递,比如 a 的别名是 bb 的别名是 c,则 c 也是 a 的别名

	// alias -> name
	private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

registerAlias(String name, String alias)

	public void registerAlias(String name, String alias) {
		Assert.hasText(name, "'name' must not be empty");
		Assert.hasText(alias, "'alias' must not be empty");
		
		synchronized (this.aliasMap) {
			// name 与 别名 相同则移除对应别名
			if (alias.equals(name)) {
				this.aliasMap.remove(alias);
				if (logger.isDebugEnabled()) {
					logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
				}
			}
			else {
				String registeredName = this.aliasMap.get(alias);

				// 别名已存在
				if (registeredName != null) {
					if (registeredName.equals(name)) {
						return;
					}

					// 不允许覆盖则抛异常,默认允许
					if (!allowAliasOverriding()) {
						throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
								name + "': It is already registered for name '" + registeredName + "'.");
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
								registeredName + "' with new target name '" + name + "'");
					}
				}

				// 检查是否由循环别名,即 a 的别名是 b,b 的别名又是 a
				checkForAliasCircle(name, alias);

				// 维护 alias -> name 关系
				this.aliasMap.put(alias, name);
				if (logger.isTraceEnabled()) {
					logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
				}
			}
		}
	}

	// 是否允许别名覆盖,默认 true,可由子类复写
	protected boolean allowAliasOverriding() {
		return true;
	}

别名的注册,基于 Map 实现,逻辑并不复杂,值得注意的是:

  • 别名与原名相同,则注解移除对应别名
  • 对于已经存在的别名,是否覆盖取决于 allowAliasOverriding,换句话说,可以复写此类自定义覆盖逻辑
  • 不允许别名循环

removeAlias(String alias)

	// 基于 Map 移除
	public void removeAlias(String alias) {
		synchronized (this.aliasMap) {
			String name = this.aliasMap.remove(alias);
			if (name == null) {
				throw new IllegalStateException("No alias '" + alias + "' registered");
			}
		}
	}

没有指定别名的话会抛出 IllegalStateException

isAlias(String name)

	// 基于 Map 判断
	public boolean isAlias(String name) {
		return this.aliasMap.containsKey(name);
	}

getAliases(String name)

	// 获取 name 的所有别名
	public String[] getAliases(String name) {
		List<String> result = new ArrayList<>();
		synchronized (this.aliasMap) {
			retrieveAliases(name, result);
		}
		return StringUtils.toStringArray(result);
	}

	// 递归查找,即 name 的 别名的(别名的...)别名也算
	private void retrieveAliases(String name, List<String> result) {
		this.aliasMap.forEach((alias, registeredName) -> {
			if (registeredName.equals(name)) {
				result.add(alias);
				retrieveAliases(alias, result);
			}
		});
	}

支持别名传递,借助一个小递归实现

resolveAliases(StringValueResolver valueResolver)

	// 解析对应的 alias 和 name 后注册
	public void resolveAliases(StringValueResolver valueResolver) {
		synchronized (this.aliasMap) {
			Map<String, String> aliasCopy = new HashMap<>(this.aliasMap);

			// 遍历所有已注册的别名
			aliasCopy.forEach((alias, registeredName) -> {

				// 用 valueResolver 解析所有 KV
				String resolvedAlias = valueResolver.resolveStringValue(alias);
				String resolvedName = valueResolver.resolveStringValue(registeredName);

				// 解析为 null 或者 解析结果相等则移除对应别名
				if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) {
					this.aliasMap.remove(alias);
				}
				else if (!resolvedAlias.equals(alias)) {

					// alias 解析后变了,则注册解析后的 KV
					String existingName = this.aliasMap.get(resolvedAlias);
					if (existingName != null) {
						if (existingName.equals(resolvedName)) {
							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);
				}
			});
		}
	}

StringValueResolver 处理所有已注册的别名,如果有必要,重新注册

  • 这主要是针对比如 Spring 环境中的 占位符 解析
  • 对解析过后的别名(原名),如果解析结果为 null,或者别名和原名相同了,又或者解析后的结果已经注册过了,那直接移除就好了
  • 否则,重新注册

canonicalName(String name)

	// 解析别名的原名
	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;
	}

这个方法应该是最常用了:根据指定别名获取原名,鉴于别名可以传递,它的实现逻辑就是一直追溯到底了

demo

	@Test
    public void test() {

        SimpleAliasRegistry registry = new SimpleAliasRegistry();
        registry.registerAlias("a", "A");
        registry.registerAlias("A", "1");

        System.out.println(registry.isAlias("a"));
        System.out.println(registry.isAlias("A"));
        System.out.println(registry.isAlias("1"));

        System.out.println(registry.canonicalName("A"));
        System.out.println(registry.canonicalName("1"));
    }

示例代码加深理解

BeanDefinitionRegistry

public interface BeanDefinitionRegistry extends AliasRegistry {

	// 注册指定 BeanDefinition,必须支持 RootBeanDefinition 和 ChildBeanDefinition
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	// 移除指定 name 对应的 BeanDefinition
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	// 获取指定 name 对应的 BeanDefinition
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	// 是否包含指定 name 对应的 BeanDefinition
	boolean containsBeanDefinition(String beanName);

	// 获取所有 BeanDefinition 的 name
	String[] getBeanDefinitionNames();

	// 返回 BeanDefinition 数量
	int getBeanDefinitionCount();

	// 确定给定 beanName 是否早已注册
	// 换句话说,给定 beanName(或者别名)对应的 bean实例 已被注册
	boolean isBeanNameInUse(String beanName);

}
  • BeanDefinitionRegistry,充当 BeanDefinition 的注册中心,定义了 BeanDefinition 管理的基本方法
  • 不难理解,BeanDefinition 也有别名的概念,因此它也是 AliasRegistry 的子接口

总结

无论我们注册 bean实例,亦或注册 BeanDefinition,都是有别名概念的,对应机制便由 AliasRegistry 提供,具体逻辑可见实现类 SimpleAliasRegistry:基于 Map 管理,并不复杂