一、spring-beans
1、目录结构
我们先来看看bean包,目录结构如下:
2、核心类DefaultListableBeanFactory
bean包中有个核心类DefaultListableBeanFactory,是bean加载的核心部分,层次结构如下:
今天先来看下AliasRegistry&SimpleAliasRegistry。
二、AliasRegistry&SimpleAliasRegistry概述
AliasRegistry:是个接口,定义对别名的简单增删等操作。
SimpleAliasRegistry:是AliasRegistry的实现,主要是用了一个map对别名进行缓存。
首先来看AliasRegistry,它定义了4个方法,方法的作用和参数含义,注释写的很清楚,这里就不画蛇添足了。
/**
* Return the aliases for the given name, if defined.
* @param name the name to check for aliases
* @return the aliases, or an empty array if none
*/
String[] getAliases(String name);
/**
* Determine whether this given name is defines as an alias
* (as opposed to the name of an actually registered component).
* @param name the name to check
* @return whether the given name is an alias
*/
boolean isAlias(String name);
/**
* Given a name, register an alias for it.
* @param name the canonical name
* @param alias the alias to be registered
* @throws IllegalStateException if the alias is already in use
* and may not be overridden
*/
void registerAlias(String name, String alias);
/**
* Remove the specified alias from this registry.
* @param alias the alias to remove
* @throws IllegalStateException if no such alias was found
*/
void removeAlias(String alias);
三、实现类SimpleAliasRegistry解析
1、变量定义
/** Map from alias to canonical name */
private final Map
1)为什么加上final前缀
正如“除非需要更高的可见性,否则应将所有的域都声明为私有域”是一个良好的编程习惯,“除非需要某个域是可变的,否则应将其声明为final域”也是一个良好的编程习惯。
--引自Java并发编程
我的理解是在满足实际需求的情况下,尽量缩小一个类或者一个变量的可变范围,减少程序中的可变状态。可变状态越少,需要维护的工作量就越少,一个极端情况是定义了一个不可变类,即类的状态在初始化后就被决定,之后永远不会改变,显然它是线程安全的,并且不需要我们为了保证线程安全做额外的工作。
2)ConcurrentHashMap<>(16)
可以参阅下面三篇博文,写的很好,在这儿就不讲了。
Map 综述(三):彻头彻尾理解 ConcurrentHashMap
https://blog.csdn.net/justloveyou_/article/details/72783008
ConcurrentHashMap实现原理及源码分析
https://www.cnblogs.com/chengxiao/p/6842045.html
在元素的装载数量明确的时候HashMap的大小应该如何选择
https://www.cnblogs.com/coderxuyang/p/3718856.html
3)工具类Assert&StringUtils
这两个工具类封装的都很巧妙
类都设置为抽象类:因为方法都是static方法,不需要实例,通过类就可以直接调用方法,所以将类设计为abstract很巧妙,abstract类正好不能被实例化。
校验不通过抛异常:校验不通过抛异常,而不是返回错误码。如果用错误码,在调用此方法的层次上,还需要有一层判断。当然采用哪种方式需要根据实际场景来定。
将错误信息封装在异常中:这样捕获异常后,根据封装的信息就可以知道错误的原因。
4)StringUtils.hasText
这个工具类需要学习的地方是在判断hasText时,多了一步containText判断,如果所有的字符都是空格,那等于是没有信息的。在实际编码中,大多数是少了这个判断的,当然这个需要根据实际的场景,如果允许所有的字符都为空格,那就另当别论了。
public static boolean hasText(@Nullable String str) {
return (str != null && !str.isEmpty() && containsText(str));
}
private static boolean containsText(CharSequence str) {
int strLen = str.length();
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(str.charAt(i))) {
return true;
}
}
return false;
}
5)ConcurrentHashMap为什么还要synchronized
aliasMap已经定义为ConcurrentHashMap,而ConcurrentHashMap是线程安全的,那为什么还要synchronized ?原因是aliasMap只能保证 this.aliasMap.remove(alias)的操作的原子性,不能保证如下复合操作的原子性,也就不能保证如下代码的线程安全。
synchronized (this.aliasMap) {
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
}
else {
。。。。。。
}
而下面的方法只有一行this.aliasMap.containsKey(name); aliasMap又是线程安全的,也就保证isAlias的线程安全。
public boolean isAlias(String name) {
return this.aliasMap.containsKey(name);
}
6)checkForAliasCircle
这是一个protected方法,自身、子类及同一个包中类可以访问。
方法里面调用了一个hasAlias方法,这个方法用了一个递归,设计的很巧妙。
在遇到下面的情况时,就会抛出异常。