当前位置: 首页 > news >正文

探究Spring的单例设计模式--单例Bean

Spring的单例设计模式

在Spring框架中,单例设计模式是一种常见且重要的设计模式,主要用于确保在应用程序的生命周期中仅创建一个特定的Bean实例

一、什么是单例设计模式?

单例设计模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。这种模式的核心在于控制实例的创建,避免了因为多次创建对象导致的资源浪费。单例模式通常用于以下场景:

  1. 节约资源:在需要大量创建相同对象时,使用单例可以显著减少内存消耗。

  2. 全局访问:单例模式提供了一个全局访问点,使得在任何地方都能轻松获取到该实例,避免了需要通过参数传递对象的复杂性。

  3. 协调操作:在某些情况下,多个对象需要共享状态或资源,单例模式能够确保所有对象都访问到相同的数据。

在Spring框架中,单例Bean是默认的Bean作用域。开发者定义的Bean如果没有显式指定作用域,Spring容器将自动将其视为单例。Spring通过内置的机制管理单例Bean的创建和访问,确保应用在运行时始终只有一个实例。

这种设计模式使得Spring的开发者可以专注于业务逻辑,而不必担心实例化和管理对象的细节。Spring通过依赖注入(DI)机制,将单例Bean的实例注入到需要它的类中,提供了简单而强大的方式来共享对象。

二、Spring中的单例Bean

在Spring中,当我们定义一个Bean时,如果没有指定作用域,它默认是单例的。以下是一个简单的示例:

import org.springframework.stereotype.Component;@Component
public class MySingletonBean {public MySingletonBean() {System.out.println("MySingletonBean instance created");}public void doSomething() {System.out.println("Doing something...");}
}

在这个示例中,MySingletonBean是一个单例Bean。当Spring容器启动时,它会创建这个Bean的唯一实例。

三、单例Bean的实现原理

在Spring框架中,单例Bean的实现依赖于Spring容器的管理机制:

1.单例Bean的创建

Spring容器负责Bean的实例化、配置和生命周期管理。单例Bean的创建主要在AbstractAutowireCapableBeanFactory类中进行。具体的创建流程如下:

  1. Bean定义的注册:首先,在Spring容器启动时,所有的Bean定义(包括其元数据)会被注册到DefaultListableBeanFactory中。

  2. Bean的实例化:当一个Bean被请求时,Spring会检查是否已经存在该Bean的实例。对于单例Bean,Spring在第一次请求时会创建实例,并将其存储在缓存中。

2.源码解析

下面是Spring源码中与单例Bean管理相关的几个重要部分:

3.单例Bean的生命周期管理

除了实例化,Spring还负责单例Bean的生命周期管理,包括:

初始化:Bean被实例化后,可以执行初始化方法,例如通过@PostConstruct注解或实现InitializingBean接口。

销毁:在容器关闭时,Spring会调用单例Bean的销毁方法,例如通过@PreDestroy注解或实现DisposableBean接口。

  1. Bean的创建逻辑:在AbstractAutowireCapableBeanFactory中,doGetBean方法负责获取Bean实例。以下是部分代码片段:

    @Override
    protected <T> T doGetBean(String name, Class<T> requiredType, Object[] args) {// 检查缓存Object bean = getSingleton(name);if (bean != null) {return (T) bean;}// 如果缓存中不存在,则创建新实例// 省略 Bean 实例化逻辑bean = createBean(name, mbd, args);// 将创建的 Bean 存入缓存registerSingleton(name, bean);return (T) bean;
    }​
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "'beanName' must not be null");synchronized (this.singletonObjects) {// 检查缓存中是否存在实例Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {//...省略了很多代码try {singletonObject = singletonFactory.getObject();}//...省略了很多代码// 如果实例对象在不存在,我们注册到单例注册表中。addSingleton(beanName, singletonObject);}return (singletonObject != NULL_OBJECT ? singletonObject : null);}}//将对象添加到单例注册表protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));}}
    }​
    
    • getSingleton(name):检查是否存在该Bean的实例。
    • createBean(name, mbd, args):创建新的Bean实例。
    • registerSingleton(name, bean):将新创建的Bean注册到单例缓存中。
  2. 单例缓存:Spring使用singletonObjects集合来缓存单例Bean实例,具体在DefaultSingletonBeanRegistry中定义:

    protected final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    1. 当一个单例Bean被创建后,Spring会将其实例存储在这个singletonObjects映射中,以便后续请求时直接返回。
  3. 线程安全:Spring确保单例Bean在多线程环境中的安全性。对于单例Bean的创建,通常会在关键部分添加同步机制,以防止多个线程同时创建实例。例如,在创建单例Bean时,Spring会使用synchronized关键字来保证线程安全。

四、总结

Spring的单例设计模式通过确保Bean在整个应用程序中只有一个实例,提供了高效的资源管理和简化的访问方式。理解单例Bean的实现原理及其在多线程环境中的安全性,对于开发高效的Spring应用至关重要。

相关文章:

  • 25中国烟草校园招聘面试问题总结 烟草面试全流程及面试攻略
  • 国外电商系统开发-需求记录
  • 【C++】异常处理
  • Android Stuido中编译信息出现乱码的解决方式
  • ClickHouse | 查询
  • C++ | Leetcode C++题解之第446题等差数列划分II-子序列
  • 最大正方形 Python题解
  • 第二十三节:学习拦截器或者使用AOP实现用户token参数请求检测(自学Spring boot 3.x的第六天)
  • IDEA几大常用AI插件
  • springboot+satoken实现刷新token(值变化)
  • STL之stackqueue篇(上)探索C++ STL中的Queue与Stack——构建数据处理的基础框架
  • django drf to_representation
  • NVIDIA Hopper 架构深入
  • 刷题学习日记 (1) - SWPUCTF
  • Python FFmpeg 安装使用教程
  • CSS居中完全指南——构建CSS居中决策树
  • github指令
  • Redux 中间件分析
  • Theano - 导数
  • 初识 webpack
  • 当SetTimeout遇到了字符串
  • 给第三方使用接口的 URL 签名实现
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 你不可错过的前端面试题(一)
  • 排序(1):冒泡排序
  • 区块链共识机制优缺点对比都是什么
  • 提醒我喝水chrome插件开发指南
  • 微信小程序实战练习(仿五洲到家微信版)
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • #《AI中文版》V3 第 1 章 概述
  • #APPINVENTOR学习记录
  • (07)Hive——窗口函数详解
  • (2024.6.23)最新版MAVEN的安装和配置教程(超详细)
  • (C++17) std算法之执行策略 execution
  • (备份) esp32 GPIO
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (离散数学)逻辑连接词
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (十) 初识 Docker file
  • (十八)SpringBoot之发送QQ邮件
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (五)网络优化与超参数选择--九五小庞
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .NET C# 配置 Options
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET 项目中发送电子邮件异步处理和错误机制的解决方案
  • .net6使用Sejil可视化日志
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .NET与java的MVC模式(2):struts2核心工作流程与原理