![设计模式就该这样学:基于经典框架源码和真实业务场景](https://wfqqreader-1252317822.image.myqcloud.com/cover/758/33114758/b_33114758.jpg)
8.3 单例模式在框架源码中的应用
8.3.1 单例模式在JDK源码中的应用
首先来看JDK的一个经典应用Runtime类,源码如下。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt010_72.jpg?sign=1738973600-T6d4SV4mzdwB1KI01r2kgJNH9Ox9lQTR-0-e14fdf086a93af480f3d6b2ea2cc439a)
8.3.2 单例模式在Spring源码中的应用
接下来看单例模式在Spring中的应用,Spring中加载单例的过程都是在BeanFactory的getBean()方法中被定义的,其默认的功能实现在AbstractBeanFactory中,主要包含两个功能。
(1)从缓存中获取单例Bean。
(2)从Bean的实例中获取对象。
getBean()方法最终会调用AbstractBeanFactory的doGetBean()方法,源码如下。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt010_73.jpg?sign=1738973600-3YlHpQn5KZmgabKTRxHQiYFL3w8nW76B-0-37a12e78a6b867cc14836542d38ea4a5)
getBean()方法不仅处理单例对象的逻辑,还处理原型对象的逻辑。继续看getSingleton()方法的代码实现。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt010_74.jpg?sign=1738973600-ATjRiMpJ3apTXT6BfClFzGtg7fM39SUR-0-b544f31037f35be67eee53d817529e2c)
在上面代码片段中,synchronized(this.singletonObjects)是关键,但是前提条件isSingletonCurrentlyInCreation的返回值也是true,也就是这个Bean正在被创建。因此,第一次调用doGetBean()的时候,getSingleton()基本上都是返回null,所以会继续执行doGetBean()方法中后面的逻辑。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt010_75.jpg?sign=1738973600-O8rJq5xgw7uzjI9KOQxxoTxkgEuLlvS9-0-f14251e2ff9f929aa0fd245bb1412f07)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt010_76.jpg?sign=1738973600-Tg9O9L6dhIUQYC0qpiqOhYlQDa9bUzzq-0-c02d05224b826c035f3456ccf43942fe)
可以看到,在BeanFactory中,从XML中解析出来的相关配置信息被放在BeanDefinitionMap中,通过这个Map获取RootBeanDefinition,然后执行判断语句if(mbd.isSingleton())。如果是单例的,则接着调用getSingleton()的重载方法,传入mbd参数。当从缓存中加载单例对象时,会把当前的单例对象在singletonObjects中存放一份,这样可以保证在调用getBean()方法的时候,singletonObjects中永远只有一个实例,在获取对象时才会给它分配内存,既保证了内存高效利用,又是线程安全的。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt010_77.jpg?sign=1738973600-6OEKoz22etsMpFL84Jfeorr1oHUh5FG8-0-13908cc7da271a278b284ce169d307e4)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt010_78.jpg?sign=1738973600-X3sl5qiWUkmZ2MvqgJebe4LPWtRZKmg4-0-43ab87745712697af864991e12e07c8d)
如此一来,当下次需要这个单例Bean时,可以直接从缓存中获取。在Spring中创建单例的过程虽然有点绕,但是逻辑非常清楚,就是将需要的对象放在Map中,下次需要的时候直接从Map中获取即可。