【源码】Spring —— AliasRegistry BeanDefinitionRegistry 解读
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
AliasRegistry 别名管理的顶层接口,BeanDefinitionRegistry 是 AliasRegistry 下一个核心的分支,抽象了 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 的别名是 b,b 的别名是 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 管理,并不复杂