Spring源码阅读2:AliasRegistry&SimpleAliasRegistry

一、spring-beans


1、目录结构

我们先来看看bean包,目录结构如下:

Spring源码阅读2:AliasRegistry&SimpleAliasRegistry_第1张图片


2、核心类DefaultListableBeanFactory


bean包中有个核心类DefaultListableBeanFactory,是bean加载的核心部分,层次结构如下:

Spring源码阅读2:AliasRegistry&SimpleAliasRegistry_第2张图片

今天先来看下AliasRegistry&SimpleAliasRegistry。


二、AliasRegistry&SimpleAliasRegistry概述


AliasRegistry是个接口,定义对别名的简单增删等操作。

SimpleAliasRegistry是AliasRegistry的实现,主要是用了一个map对别名进行缓存。


首先来看AliasRegistry,它定义了4个方法,方法的作用和参数含义,注释写的很清楚,这里就不画蛇添足了。

Spring源码阅读2:AliasRegistry&SimpleAliasRegistry_第3张图片

/**

* 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 aliasMap = new ConcurrentHashMap<>(16);

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方法,自身、子类及同一个包中类可以访问。

Spring源码阅读2:AliasRegistry&SimpleAliasRegistry_第4张图片

方法里面调用了一个hasAlias方法,这个方法用了一个递归,设计的很巧妙。

Spring源码阅读2:AliasRegistry&SimpleAliasRegistry_第5张图片

在遇到下面的情况时,就会抛出异常。

Spring源码阅读2:AliasRegistry&SimpleAliasRegistry_第6张图片


Spring源码阅读2:AliasRegistry&SimpleAliasRegistry_第7张图片



你可能感兴趣的:(Spring)