别名在现实世界处处存在,更有着取个英文名,什么 wiket、sophy 等,叫起来也挺顺耳的。不仅仅在姓名上取别名,连编程上都使用了,嘿,把 "wiket" 地址给我,Spring 查找了一遍,在别名模块找了指定的对象....
别名是对象标识的另一个称呼,与对象一一对应。
AliasRegistry:制定别名的管理规则:
public interface AliasRegistry {
// 给名称注册一个别名
void registerAlias(String name, String alias);
// 删除一个别名
void removeAlias(String alias);
// 给定名称的别名是否存在
boolean isAlias(String name);
// 获取给定名称的别名
String[] getAliases(String name);
}
接下来看下 AliasRegistry 实现类有哪些:
AbstractAutowireCapableBeanFactory.java
AbstractBeanFactory.java
AnnotationConfigApplicationContext.java
AnnotationConfigEmbeddedWebApplicationContext.java
BeanDefinitionRegistry.java
DefaultListableBeanFactory.java
DefaultSingletonBeanRegistry.java
EmbeddedWebApplicationContext.java
FactoryBeanRegistrySupport.java
GenericApplicationContext.java
GenericGroovyApplicationContext.java
GenericWebApplicationContext.java
GenericXmlApplicationContext.java
ResourceAdapterApplicationContext.java
SimpleAliasRegistry.java
SimpleBeanDefinitionRegistry.java
StaticApplicationContext.java
StaticWebApplicationContext.java
XmlEmbeddedWebApplicationContext.java
接下来看下如何使用:
<bean name="some" class="MDJBean.Car"/>
<alias name="some" alias="someBean"/>
<alias name="some" alias="oneBean"/>
一个名字可以关联多个别名。是一种一对多的关系。
接下来看 AliasRegistry 接口的基本实现类 SimpleAliasRegistry:
public class SimpleAliasRegistry implements AliasRegistry {
protected final Log logger = LogFactory.getLog(getClass());
//[别名-名称]的映射容器
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)) { //已存在则不做任何处理
return;
}
if (!allowAliasOverriding()) { // 是否允许覆盖
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
// alias是否已存在
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}
}
/**
* alias是否已存在,已存在则抛出IllegalStateException异常
*/
protected void checkForAliasCircle(String name, String alias) {
// 注意hasAlias的入参
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");
}
}
/**
* 指定alias是否已存在
*/
public boolean hasAlias(String name, String alias) {
for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
String registeredName = entry.getValue();
/**
* 禁止的两种情况:
* 1、map容器(carA:car),指定(carA,car)
* 2、map容器(carA:car,carC:carA),指定(carC,car)
*/
if (registeredName.equals(name)) {
String registeredAlias = entry.getKey();
if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {
return true;
}
}
}
return false;
}
// alias是否允许被覆盖,默认为可以
protected boolean allowAliasOverriding() {
return true;
}
// 移除别名
@Override
public void removeAlias(String alias) {
synchronized (this.aliasMap) {
String name = this.aliasMap.remove(alias); //移除动作
if (name == null) { // 被移除的alias不存在则抛出异常
throw new IllegalStateException("No alias '" + alias + "' registered");
}
}
}
/**
* 重构容器
*/
public void resolveAliases(StringValueResolver valueResolver) {
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);
// 变换后alias || name为null || alias和name一样,则移除
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) { // 对应别名存在,移除或抛出异常
// 容器中已存在变换后的alias
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 + "'.");
}
// 容器中不存在变换后的alias,
checkForAliasCircle(resolvedName, resolvedAlias);
// 移除旧的alias
this.aliasMap.remove(alias);
// 添加变换后的alisa-name对
this.aliasMap.put(resolvedAlias, resolvedName);
}
else if (!registeredName.equals(resolvedName)) {
this.aliasMap.put(alias, resolvedName);
}
});
}
}
/**
* 获取原始名称,如果传进来是别名的则获取对应的名称
*
* 这里使用do-while情况:[A->B B->C] => [(A and B)->C]
* 查找过程:通过A找到B,再通过B找到C
*/
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
}
在验证别名正确性的流程中,不允许出现环路:
<bean name="B" class="MDJBean.Car"/>
<bean name="C" class="MDJBean.Car"/>
<alias name="B" alias="A"/> // A->B
<alias name="C" alias="B"/> // B->C
==> (A & B)->C
<bean name="B" class="MDJBean.Car"/>
<bean name="A" class="MDJBean.Car"/>
<alias name="B" alias="A"/> // A->B
<alias name="A" alias="C"/> // C->A
==> (A & C->B)
如上图,如果 (A & B) ->C,定义一个 C->A 的关系,这时候出现环路,这是不允许出现的情况,直接抛出异常。
所以 hasAlias() 方法则是查找待设置的别名关系是否会导致环路出现,如下所示:
思考:
- 通过 alias 可以获取指定 bean 的实例,它是获取 bean 实例的另一种方式;
- 别名和名称不能一样,一样则被移除。名字叫张三的童孩,别名也是张三,这样别名就没有任何意义了;
- 可以对指定的 bean 创建多个 alias,bean 与 alias 是一对多的关系;
- bean 之间不允许环路 alias,即 A - > B,B - > C,C - > A;
- 针对(A->B B->C) => (A & B->C)在哪一步做处理了?