Spring源码学习--bean加载之名字转化与缓存中获取单例bean

名字转化

名字转化是sping加载的第一步,为什么存在名字转化这个步骤呢,原因有一下两点:

  1. spring支持每个bean存在别名,并支持使用别名加载bean,所以这里需要对别名的一个转化.
  2. 如果spring想加载工厂bean而不是工厂生成的bean时,那么会在beanName名字前加&, 所以也需要除去& 才能获取bean.

针对以上两个需求,spring的名字转化就是解决这两个问题.具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
final String beanName = transformedBeanName(name);

protected String transformedBeanName(String name) {
//1. BeanFactoryUtils.transformedBeanName(name) 是除去&
//2. 获取真实beanName
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

// 1.
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
String beanName = name;
//FACTORY_BEAN_PREFIX = "&";
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}

//2.
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {//别名递归定义,从中找到真实的bean. bean在aliasMap里没有注册.所以真实的beanName aliasMap.get()时是null.
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}while (resolvedName != null);


return canonicalName;
}
  1. 去除&, 这个相对比较简单,就是字符串的操作.如果判断beanName是以&开头的,直接除去该部分得到一个新的字符串.
  2. 别名事前已经被注册在缓存中了,只要递归地调用map的get方法,直到获取的value为null时,该key就是真实的beanName.

缓存中获取单例bean

spring为了解决bean属性循环依赖问题,会提早将创建bean的ObjectFactory曝光,曝光过程在后面会介绍.spring首先会从从缓存中获取或从缓存工厂(曝光的OjectFactory缓存)中获取bean,这样可以不等前一个bean创建完就可以直接使用暴露的工厂生成一个新的bean.
这里首先需要介绍下DefaultSingltonBeanRegistry的一些相关数据结构.

1
2
3
4
5
6
7
8
9
10
11
//单例,保存已经创建完成的单例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
//是提早曝光的bean工厂,可以通过该工厂创建bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
//为了解决循环依赖问题,spring采用了提早暴露的方法.将提早暴露的单例存放在这里.
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
//存放正在创建的bean,
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
//所有注册的单例bean 的名字
private final Set<String> registeredSingletons = new LinkedHashSet<String>(64);

spring首先回去缓存中查看是否该bean已经完成创建.如果不存在并且该bean正在创建中,则尝试去提早曝光的bean缓存earlySingletonObjects中获取.如果还是没有那么,看看是否允许提早曝光,如果允许并且已经提早曝光了创建这个bean的工厂ObjectFactory. 则使用这个曝光的工厂生成bean,保存到earlySingletonObjects并返回.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从单例缓冲中获取bean
Object singletonObject = this.singletonObjects.get(beanName);
//如果缓冲不存在,并且当前正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//看是否在earlySingletonObjects中 
singletonObject = this.earlySingletonObjects.get(beanName);
//如果不存在并且运行 提早引用
if (singletonObject == null && allowEarlyReference) {
//当某些方法需要提前初始化的时候则会调用addSingletonFactory 方法将对应的ObjectFactory
//初始化策略存储在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//注册表不存放该bean 
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);//创建完 删除该单例工厂.
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
0%