单例模式在JDK和Spring源码中的应用
本节主要介绍单例模式在 JDK 和 Spring 源码中的应用。
在 Spring 中,bean 可以被定义为两种模式:prototype(多例)和 singleton(单例)。
Spring 中加载单例的过程都是在 BeanFactory 的 getBean() 方法中被定义的,其默认的功能在 AbstractBeanFactory 类中实现,主要包含两个功能。
getBean() 方法最终会调用 AbstractBeanFactory 的 doGetBean() 方法,源码如下。
getSingleton() 的工作流程:singletonObjects-->earlySingletonObjects-->singletonFactories-->创建单例实例
单例模式在JDK源码中的应用
JDK 中 Runtime 类使用了单例模式,源码如下。public class Runtime { private static java.lang.Runtime currentRuntime = new java.lang.Runtime(); public static java.lang.Runtime getRuntime() { return currentRuntime; } private Runtime() {} ... }
单例模式在Spring源码中的应用
下面介绍单例模式在 Spring 中的应用。在 Spring 中,bean 可以被定义为两种模式:prototype(多例)和 singleton(单例)。
- singleton(单例):只有一个共享的实例存在,所有对这个 bean 的请求都会返回唯一的实例。
- prototype(多例):对这个 bean 的每次请求都会创建一个新的 bean 实例,类似于 new。
实例
配置文件内容如下:
<bean id="singleton" class="java.util.Date" scope="singleton"></bean>
<bean id="prototype" class="java.util.Date" scope="prototype"></bean>
public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Date s1 = (Date) context.getBean("singleton"); Date s2 = (Date) context.getBean("singleton"); Date p1 = (Date) context.getBean("prototype"); Date p2 = (Date) context.getBean("prototype"); System.out.println("单例:" + (s1 == s2)); System.out.println("多例:" + (p1 == p2)); } }运行结果如下:
单例:true
多例:false
Spring 中加载单例的过程都是在 BeanFactory 的 getBean() 方法中被定义的,其默认的功能在 AbstractBeanFactory 类中实现,主要包含两个功能。
- 从缓存中获取单例 Bean。
- Bean 的实例中获取对象。
getBean() 方法最终会调用 AbstractBeanFactory 的 doGetBean() 方法,源码如下。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //对传入的beanName稍作修改,防止有一些非法字段,然后提取Bean的Name final String beanName = transformedBeanName(name); Object bean; //直接从缓存中获取单例工厂中的objectFactory单例 Object sharedInstance = getsingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { } } //返回对应的实例,从 Bean实例中获取对象 bean = getObjectForBeanInstance(sharedInstance,name,beanName, null); } else { ... } ... }getBean() 方法不仅处理单例对象的逻辑,还处理原型对象的逻辑。继续看 getSingleton() 方法的代码实现。
getSingleton() 的工作流程:singletonObjects-->earlySingletonObjects-->singletonFactories-->创建单例实例
/** * 单例对象的缓存 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); protected Object getSingleton(String beanName, boolean allowEarlyReference) { //首先通过名字查找这个Bean是否存在 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { //查看缓存中是否存在这个Bean singletonObject = this.earlySingletonObjects.get(beanName); //如果这个时候的Bean实例还为空并且允许懒加载 if (singletonObjects == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }在上面代码片段中,synchronized(this.singletonObjects) 是关键,但是前提条件 isSingletonCurrentlyInCreation 的返回值也是 true,也就是这个 Bean 正在被创建。因此,第一次调用 doGetBean() 的时候,getSingleton() 基本上都是返回 null,所以会继续执行 doGetBean() 方法中后面的逻辑。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 获取beanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } } ... } }可以看到,在 BeanFactory 中,从 XML 中解析出来的相关配置信息被放在 BeanDefinitionMap 中,通过这个 Map 获取 RootBeanDefinition,然后执行判断语句if(mbd.isSingleton())。如果是单例的,则接着调用 getSingleton() 的重载方法,传入 mbd 参数。当从缓存中加载单例对象时,会把当前的单例对象在singletonObjects 中存放一份,这样可以保证在调用 getBean() 方法的时候,singletonObjects 中永远只有一个实例,在获取对象时才会给它分配内存,既保证了内存高效利用,又是线程安全的。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { // 直接从缓存中获取单例Bean Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { // 在singletonObject中添加要加载的单例 addSingleton(beanName, singletonObject); } } return singletonObject; } }如此一来,当下次需要这个单例 Bean 时,可以直接从缓存中获取。在 Spring 中创建单例的过程虽然有点绕,但是逻辑非常清楚,就是将需要的对象放在 Map 中,下次需要的时候直接从 Map 中获取即可。
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算