Spring Boot的单例模式实现代码

 更新时间:2026年03月17日 09:23:21   作者:程序员飞鱼  
Spring Boot里的单例不是GoF意义上的全JVM 唯一对象 + 私有构造器,而是由 Spring 容器管理的每个 ApplicationContext 仅一个实例,本文介绍Spring Boot的单例模式是如何实现的,感兴趣的朋友跟随小编一起看看吧

Spring Boot 里的单例不是 GoF 意义上的全 JVM 唯一对象 + 私有构造器。

而是由 Spring 容器管理的每个 ApplicationContext 仅一个实例

其本质是 IOC 容器用缓存表保存已创建的 Bean,并在 getBean() 时复用。

默认就是单例

  • 任何 @Component / @Service / @Repository / @Controller,或 @Bean默认 scope=singleton
  • 单例是容器级别:多个 ApplicationContext(测试、子上下文)各有一份。
@Component // 等价于 @Scope("singleton")
public class UserService {}

容器如何保证只有一个

核心在 DefaultSingletonBeanFactory/DefaultSingletonBeanRegistry三级缓存与同步控制:

  • 一级缓存 singletonObjects:已完全创建好的单例。
  • 二级缓存 earlySingletonObjects:为解决循环依赖而“提前曝光”的半成品对象。
  • 三级缓存 singletonFactories:可生成早期引用的工厂(通常是 AOP 代理工厂)。

创建流程(简化):

  1. getBean(name) → 若在 singletonObjects 里,直接返回。
  2. 不在 → 标记“正在创建”,调用 createBean() 完成实例化、依赖注入、BeanPostProcessor 等。
  3. 初始化完成后放入 singletonObjects,清理二/三级缓存,返回单例。
  4. 全过程对同名 bean 的创建有同步锁,避免并发重复创建,并通过早期引用解决 A→B→A 的构造/注入级循环依赖

何时创建

  • 默认容器刷新时预创建(preInstantiateSingletons())。
  • 标注 @Lazy 或全局开启 spring.main.lazy-initialization=true 时,延迟到首次 getBean() 才创建,但仍是单例

线程安全与可见性

  • 创建阶段受容器同步保护,发布到 singletonObjects 前已完成依赖注入与后置处理,具备安全发布语义。
  • 单例是多线程共享:业务字段若是可变状态,需自行保证线程安全(不可变、同步、并发集合等)。

@Bean@Configuration 的细节

  • @Configuration 类会被 CGLIB 增强,其 @Bean 方法默认 proxyBeanMethods=true
    • 在同一配置类内部互相调用 @Bean 方法时,调用会被拦截并从容器取同一个单例,不是 new 新对象。
  • 若显式 proxyBeanMethods=false(Spring Boot 为提速常用),同类内直接方法调用将变成普通方法调用,可能得到新对象
  • 只要是通过容器 getBean() 拿的,仍是单例。

经验:配置类间若互调 @Bean 方法,保持默认 proxyBeanMethods=true 或避免直接互调。

常见误区

  • Spring 单例 = JVM 唯一 ❌:是每个容器一个。
    • 你起了两个 ApplicationContext 就有两份。
  • 用 static/单例写法再交给 Spring 管理 ❌:多此一举且易与容器生命周期冲突。
  • 循环依赖全能解 ❌:仅能解单例构造器以外的注入型循环依赖,构造器循环、原型 scope、带代理的某些场景仍会失败。

最小验证

@SpringBootTest
class DemoTest {
    @Autowired UserService a;
    @Autowired ApplicationContext ctx;

    @Test void sameInstance() {
        UserService b = ctx.getBean(UserService.class);
        assertSame(a, b); // 同一容器内是同一个实例
    }
}

小结

Spring Boot 的单例= 默认 scope + BeanFactory 单例缓存 + 同步创建 +(必要时)早期曝光

把唯一性交给容器,比手写 GoF 单例更易测、更可控,也能与 AOP、生命周期、条件化装配等机制无缝协作。

到此这篇关于Spring Boot的单例模式实现代码的文章就介绍到这了,更多相关Spring Boot单例模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 重试框架Guava-Retry和spring-Retry的使用示例

    重试框架Guava-Retry和spring-Retry的使用示例

    spring-retry 和 guava-retry 工具都是线程安全的重试,能够支持并发业务场景的重试逻辑正确性,本文主要介绍了重试框架Guava-Retry和spring-Retry的使用示例,感兴趣的可以一下
    2023-09-09
  • Java实战之在线寄查快递系统的实现

    Java实战之在线寄查快递系统的实现

    这篇文章主要介绍了如何利用Java制作一个在线寄查快递系统,文中采用的技术有java、SpringBoot、FreeMarker、Mysql,需要的可以参考一下
    2022-02-02
  • SpringBoot实现微服务通信的多种方式

    SpringBoot实现微服务通信的多种方式

    微服务通信是指在分布式系统中,各个微服务之间进行数据交互和通信的过程,今天我们将探讨在Spring Boot中实现微服务通信的多种方式,文章通过代码示例给大家介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • Java向List集合中批量添加元素的实现方法

    Java向List集合中批量添加元素的实现方法

    这篇文章主要介绍了Java向List集合中批量添加元素的实现方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • 鸿蒙中使用WebView显示Web内容的步骤

    鸿蒙中使用WebView显示Web内容的步骤

    在鸿蒙操作系统中,Webview是一个强大的组件,它允许开发者将网页内容嵌入到应用程序中,实现与原生应用的无缝集成,这篇文章主要介绍了鸿蒙中使用WebView显示Web内容的相关资料,需要的朋友可以参考下
    2025-09-09
  • java解析dbf之通过javadbf包生成和读取dbf文件

    java解析dbf之通过javadbf包生成和读取dbf文件

    这篇文章主要介绍了java通过javadbf读取和生成DBF文件的方法,大家参考使用吧
    2014-01-01
  • SpringBoot后端验证码的实现示例

    SpringBoot后端验证码的实现示例

    为了防止网站的用户被通过密码典爆破,引入验证码的功能是十分有必要的,本文主要介绍了SpringBoot后端验证码的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • 基于注解的组件扫描详解

    基于注解的组件扫描详解

    这篇文章主要介绍了基于注解的组件扫描详解,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • Spring Mybatis Mapper模糊查询的几种方法

    Spring Mybatis Mapper模糊查询的几种方法

    在Spring结合Mybatis进行开发时,实现模糊查询是一个常见需求,在Mybatis中,LIKE查询可以通过多种方式实现,本文给大家介绍了Spring Mybatis Mapper模糊查询的几种方法,需要的朋友可以参考下
    2024-03-03
  • SpringBoot实现接口数据的加解密功能

    SpringBoot实现接口数据的加解密功能

    这篇文章主要介绍了SpringBoot实现接口数据的加解密功能,对接口的加密解密操作主要有两种实现方式,文中给大家详细介绍,需要的朋友可以参考下
    2019-10-10

最新评论