Spring源码笔记-2.4 获取单例

# 获取单例bean getSingleton

明明之前一篇已经讲过了获取单例,为什么这里又是获取单例bean呢?

两天不看书,果断又忘了.前面学的是从缓存中获取,这里是真正的获取.

DefaultSingletonBeanRegistry 中重载此方法,第二参数为ObjectFactory

 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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "'beanName' must not be null");
    	//这里再次看到了这个singletonObjects,上篇文章介绍过,是维护了单例对象
    	//书中说法是:用于保存BeanName和创建bean实例之间的关系
        Map var3 = this.singletonObjects;
        synchronized(this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
          	//首先获取一遍,如果不存在,才去创建
            if (singletonObject == null) {
              	//工厂如果正在销毁,这时候获取bean就会报错
                if (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while the singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");
                }

                if (this.logger.isDebugEnabled()) {
                  	//打印日志,正在创建单例bean(beanName)的共享的实例
                    this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                }
				//标志这个beanName正在创建,如果同时重复创建,会报错
                this.beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = this.suppressedExceptions == null;
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet();
                }

                try {
                  	//=============这里应该是最关键的创建bean的步骤===============
                    singletonObject = singletonFactory.getObject();
                  	//标识新创建出来的单例
                    newSingleton = true;
                } catch (IllegalStateException var16) {
                  	//非法状态错误,应该是创建过程中发现存在其他线程已创建此单例
                  	//所以此处catch里面再次调用了singletonObjects.get(beanName);
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw var16;
                    }
                } catch (BeanCreationException var17) {
                  	//其它创建bean错误
                    BeanCreationException ex = var17;
                    if (recordSuppressedExceptions) {
                        Iterator var8 = this.suppressedExceptions.iterator();
                        while(var8.hasNext()) {
                            Exception suppressedException = (Exception)var8.next();
                          	//把其它recordSuppressedExceptions塞入这个ex一并抛出
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                } finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                  	//确认这个beanName在几个set中的状态
                    this.afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                 	//如果是新创建的,则加入缓存,移除几个新创建的标识,名字加入registeredSingletons
                    this.addSingleton(beanName, singletonObject);
                }
            }
          	//返回,如果是NULL_OBJECT也作为null返回.
          	//这个NULL_OBJECT应该是在前面的获取方法中有可能的特殊返回值
            return singletonObject != NULL_OBJECT ? singletonObject : null;
        }
    }

从上可以看出,获取单例还是通过 synchronized(this.singletonObjects) 加锁来实现,先从 singletonObjects 查一遍有没有已存在的,若没有则再进行创建。

而创建的步骤,则是在入参的 ObjectFactory<?> 中完成,调用其 getObject() 依然还是调用我们本身AbstractBeanFactorycreateBean 方法。


我们先不急着往下看,先理一理,首先第一点要知道的是单例加锁都是 synchronized(this.singletonObjects) 。其次获取单例 bean 的大致步骤,无非就是:

  1. 上一文中介绍的,从缓存中拿,并且允许“早期引用” ,即从 earlySingletonObjects 中拿。

  2. 如果缓存中没有,则自己创建,

    2.1 在各种 map 里记录它的 创建、销毁等信息

    2.2 通过createBean 方法去具体创建这个实例。