Spring 懒加载的实际应用
引言
在 Spring 框架中,懒加载机制允许你在应用程序运行时延迟加载 Bean。这意味着 Bean 只会在第一次被请求时才实例化,而不是在应用程序启动时就立即创建。这种机制可以提高应用程序的启动速度,并节省内存资源。
Spring 的懒加载机制
- 懒加载属性:
- 在 Spring 中,可以通过在 Bean 定义中设置
lazy-init="true"属性来启用懒加载。这告诉 Spring 容器在启动时不要初始化该 Bean,而是在第一次请求时再初始化。 - 也可以通过
@Lazy注解在类级别启用懒加载。
- 在 Spring 中,可以通过在 Bean 定义中设置
- 懒加载的工作原理:
- 当 Spring 启动时,容器会读取配置文件或注解,并将 Bean 定义加载到容器中。
- 如果 Bean 被标记为懒加载,那么 Spring 不会立即实例化该 Bean。
- 当应用程序第一次尝试访问懒加载的 Bean 时,Spring 会检查容器中是否存在该 Bean 的实例。
- 如果不存在,Spring 会创建一个新的实例并将它放入容器中。
- 之后,所有的请求都将从容器中获取已存在的实例。
懒加载的适用场景
Spring 的懒加载机制是一种优化技术,它允许你在应用程序启动时不立即初始化某些 Bean,而是在第一次需要这些 Bean 时才进行初始化。这种机制可以带来几个好处,包括但不限于减少应用程序启动时间、降低内存占用以及提高系统的响应速度。
适用场景
- 大型应用程序:
- 在大型应用程序中,可能存在大量的 Bean,其中一些 Bean 可能在应用程序运行的大部分时间内都不会被使用。在这种情况下,懒加载可以避免这些 Bean 在启动时被加载,从而加快应用程序的启动速度。
- 内存敏感的应用程序:
- 对于内存敏感的应用程序,懒加载可以减少启动时的内存消耗,因为只有真正需要的 Bean 才会被加载到内存中。
- 按需加载的组件:
- 如果某些组件只在特定条件下才会被使用,那么可以将这些组件设置为懒加载。这样,除非确实需要,否则这些组件不会占用任何资源。
- 第三方库或服务:
- 如果应用程序集成了第三方库或服务,而这些库或服务在启动时会进行耗时的初始化工作,那么可以考虑将这些集成设置为懒加载。
- 性能优化:
- 对于性能要求较高的应用程序,懒加载可以帮助优化启动过程,减少不必要的初始化操作,从而提高系统响应速度。
解决的问题
- 减少启动时间:
- 通过延迟 Bean 的初始化,可以显著减少应用程序的启动时间。这对于需要快速启动的应用程序尤其重要。
- 降低内存占用:
- 懒加载可以避免一次性加载所有 Bean,从而减少应用程序的初始内存占用。这对于资源受限的环境特别有用。
- 提高性能:
- 减少启动时的初始化操作可以提高应用程序的整体性能,特别是在高负载环境下。
- 避免不必要的初始化:
- 对于那些在应用程序运行期间很少或几乎不被使用的 Bean,懒加载可以避免它们在启动时进行不必要的初始化。
- 简化部署:
- 懒加载可以简化部署过程,因为应用程序可以更快地启动并准备好接收请求。
如何启用懒加载
- 使用
@Lazy注解:- 在类级别添加
@Lazy注解,这会告诉 Spring 容器在首次请求该 Bean 时才初始化它。
- 在类级别添加
- XML 配置文件:
- 如果使用 XML 配置文件,可以为
<bean>元素添加lazy-init="true"属性来启用懒加载。
- 如果使用 XML 配置文件,可以为
- Java 配置:
- 在 Java 配置中,可以使用
@Bean方法上的@Lazy注解来启用懒加载。
- 在 Java 配置中,可以使用
示例代码
假设你有一个 LazyLoadedService 类,你希望它在第一次被请求时才初始化:
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Lazy;@Service
@Lazy
public class LazyLoadedService {public void doSomething() {System.out.println("LazyLoadedService is doing something...");}
}
在这个示例中,@Lazy 注解确保了 LazyLoadedService 只有在第一次被请求时才会被初始化。
循环依赖问题
懒加载还可以帮助解决某些类型的循环依赖问题,尤其是在 Spring 容器中。循环依赖是指两个或多个 Bean 互相依赖对方,这可能导致 Spring 在初始化这些 Bean 时出现问题。下面我将详细介绍懒加载如何帮助解决循环依赖问题,并提供一些具体的示例。
循环依赖发生在两个或多个 Bean 互相依赖的情况下。例如,假设你有两个 Bean,BeanA 和 BeanB,它们互相依赖对方:
@Service
public class BeanA {private final BeanB beanB;@Autowiredpublic BeanA(BeanB beanB) {this.beanB = beanB;}// ...
}@Service
public class BeanB {private final BeanA beanA;@Autowiredpublic BeanB(BeanA beanA) {this.beanA = beanA;}// ...
}
在 Spring 中,当容器试图初始化 BeanA 时,它需要先初始化 BeanB,而初始化 BeanB 又需要先初始化 BeanA。这导致了一个无限递归的问题。
解决方案
Spring 提供了几种机制来解决循环依赖问题:
- 使用
@Lazy注解:- 通过在至少一个 Bean 上使用
@Lazy注解,可以让 Spring 在第一次请求时才初始化这个 Bean。这可以打破循环依赖链。
- 通过在至少一个 Bean 上使用
- 利用 Spring 的代理机制(该机制在2.6.x版本之后被弃用了):
- Spring 容器可以为 Bean 创建一个代理,使得在初始化过程中可以使用代理对象而不是实际的对象。这样可以避免无限递归。
使用 @Lazy 解决循环依赖:
为了打破循环依赖,你可以将其中一个 Bean 设置为懒加载:
@Service
@Lazy
public class BeanA {private final BeanB beanB;@Autowiredpublic BeanA(BeanB beanB) {this.beanB = beanB;}// ...
}@Service
public class BeanB {private final BeanA beanA;@Autowiredpublic BeanB(BeanA beanA) {this.beanA = beanA;}// ...
}
在这个例子中,BeanA 被标记为懒加载。这意味着当 Spring 初始化 BeanB 时,它不需要立即初始化 BeanA。当第一次请求 BeanA 时,Spring 才会真正初始化它。这有效地打破了循环依赖。
Spring 处理循环依赖的代理机制:
Spring 容器在处理循环依赖时,会根据依赖的类型来决定如何解决。以下是三种不同类型的循环依赖及其处理方式:
- 构造函数注入循环依赖:
- 如果循环依赖是通过构造函数注入发生的,Spring 会使用部分构造好的对象(即尚未完全初始化的对象)来解决循环依赖。这意味着 Spring 会在构造函数注入过程中传递一个代理对象,而不是完整的 Bean 实例。
- setter 方法注入循环依赖:
- 如果循环依赖是通过 setter 方法注入发生的,Spring 会在构造完成后立刻注入代理对象,而不是完整的 Bean 实例。
- 字段注入循环依赖:
- 如果循环依赖是通过字段注入发生的,Spring 会采用与 setter 方法注入类似的方法,即在构造完成后立即注入代理对象。
在这个例子中,BeanA 和 BeanB 彼此依赖对方。Spring 会自动处理这种循环依赖,具体步骤如下:
- 初始化
BeanA:- Spring 开始初始化
BeanA,但在构造函数中需要BeanB。 - Spring 创建一个
BeanB的代理对象,并将其传递给BeanA的构造函数。
- Spring 开始初始化
- 初始化
BeanB:- Spring 开始初始化
BeanB,但在构造函数中需要BeanA。 - Spring 创建一个
BeanA的代理对象,并将其传递给BeanB的构造函数。
- Spring 开始初始化
- 完成初始化:
- 一旦
BeanA和BeanB都构造完成,Spring 会使用这些代理对象来完成它们的初始化。
- 一旦
代理对象的使用:
代理对象在初始化阶段充当实际 Bean 的占位符。这意味着 BeanA 和 BeanB 在构造时实际上持有的是代理对象,而不是实际的 Bean 实例。当这些 Bean 被真正使用时,Spring 会使用实际的 Bean 实例替换代理对象。
注意事项
- 代理机制:
- 即使使用了懒加载,Spring 仍可能为 Bean 创建代理对象来解决循环依赖问题。这意味着即使
BeanA是懒加载的,BeanB仍然可以持有指向BeanA的代理对象。
- 即使使用了懒加载,Spring 仍可能为 Bean 创建代理对象来解决循环依赖问题。这意味着即使
- 性能影响:
- 懒加载可能会稍微增加第一次请求懒加载 Bean 时的延迟,因为此时需要初始化该 Bean。
- 设计模式:
- 如果循环依赖是由于设计不当造成的,考虑重构代码以避免这种依赖关系。例如,可以使用策略模式、观察者模式等设计模式来重新组织代码。
总结
懒加载机制是一种有用的优化手段,它可以帮助提高应用程序的性能和响应能力。通过合理地使用懒加载,你可以确保应用程序在启动时只加载必要的组件,从而提高整体性能。
相关文章:
Spring 懒加载的实际应用
引言 在 Spring 框架中,懒加载机制允许你在应用程序运行时延迟加载 Bean。这意味着 Bean 只会在第一次被请求时才实例化,而不是在应用程序启动时就立即创建。这种机制可以提高应用程序的启动速度,并节省内存资源。 Spring 的懒加载机制 懒…...
PyQT 串口改动每次点开时更新串口信息
class MainWindow(QWidget, Ui_Form):def __init__(self):super().__init__(parentNone)self.setupUi(self)self.comboBox.installEventFilter(self) # 加载事件过滤器self.comboBox.addItems(get_ports())def eventFilter(self, obj, event): # 定义事件过滤器if isinstance(o…...
三级_网络技术_19_路由器的配置及使用
1.在Cisco路由器上配置DHCP服务,使得客户端可以分配到的地址范围是222.28.71.2-222.28.71.200地址租用时间是2小时30分钟,不记录地址冲突日志默认路由是222.28.71.1,分配的dns服务器地址是222.28126.27和222.28.126.26。以下配置完全正确的是…...
【STM32 Blue Pill编程】-STM32CubeIDE开发环境搭建与点亮LED
开发环境搭建与点亮LED 文章目录 开发环境搭建与点亮LED1、STM32F103C8T6及STM32 Blue Pill 介绍2、下载并安装STM32CubeIDE3、编程并点亮LED3.1 在Stm32CubeIDE中编写第一个STM32程序3.1.1 创建项目3.1.2 设备配置3.1.2.1 系统时钟配置3.1.2.2 系统调试配置3.1.2.3 GPIO配置3.…...
【数据结构】六、图:4.图的遍历(深度优先算法DFS、广度优先算法BFS)
三、基本操作 文章目录 三、基本操作1.图的遍历1.1 深度优先遍历DFS1.1.1 DFS算法1.1.2 DFS算法的性能分析1.1.3 深度优先的生成树和生成森林 1.2 广度优先遍历BFS1.2.1 BFS算法1.2.2 BFS算法性能分析1.2.3 广度优先的生成树和生成森林 1.3 图的遍历与图的连通性 1.图的遍历 图…...
29、号外!号外!ERA5再分析数据下载方式更新啦
文章目录 1. 前言2. 账号注册与协议签署2.1 账号注册2.2 签署CDS-Beta使用条款2.3 更新.cdsapi文件 3. 常见问题与解决方法(持续更新中)3.1 问题1:更新完.cdsapi文件之后,原有下载代码不可以使用3.2 问题2: RuntimeError: 403 Cli…...
智能识别,2024年SD卡数据恢复软件的智能进化
除了手机之外现在有不少的设备还是依靠SD卡来存储数据,比如相机、摄像头、无人机等。有的时候会因为一些意外的情况导致数据丢失,那是真的丢失了吗?大部分情况还是可以依靠sd卡数据恢复工具来找回这些“消失”的数据哦。 1.福昕数据恢复 链…...
浙大数据结构慕课课后题(04-树5 Root of AVL Tree)
题目要求: AVL 树是一种自平衡的二叉搜索树。在 AVL 树中,任何节点的两个子子树的高度最多相差一;如果在任何时候它们相差不止一,则进行重新平衡以恢复此属性。图 1-4 说明了旋转规则。 图1 图2 图3 图4 现在给定一系列插入,您应该…...
Golang | Leetcode Golang题解之第331题验证二叉树的前序序列化
题目: 题解: func isValidSerialization(preorder string) bool {n : len(preorder)slots : 1for i : 0; i < n; {if slots 0 {return false}if preorder[i] , {i} else if preorder[i] # {slots--i} else {// 读一个数字for i < n &&…...
zdppy+vue3+onlyoffice文档管理系统项目实战 20240812上课笔记
遗留问题 1、增加新建和导入按钮,有按钮了,但是还没有完善,图标还不对,需要解决 2、登录功能 3、用户管理 4、角色管理 5、权限管理 6、分享功能 解决新建和导入的图标问题 解决代码: <a-button type"prim…...
怎么将mov视频转换成mp4?将mov视频转换成mp4的方法
怎么将mov视频转换成mp4?由于mov格式通常与苹果设备兼容性较好,而mp4则更广泛地支持于各种播放器和设备中,因此将mov转换为mp4可以确保视频在更多场景下能够流畅播放。通过这种转换,你可以确保视频在各种平台和设备上的兼容性&…...
大数据技术——实战项目:广告数仓(第五部分)
目录 第9章 广告数仓DIM层 9.1 广告信息维度表 9.2 平台信息维度表 9.3 数据装载脚本 第10章 广告数仓DWD层 10.1 广告事件事实表 10.1.1 建表语句 10.1.2 数据装载 10.1.2.1 初步解析日志 10.1.2.2 解析IP和UA 10.1.2.3 标注无效流量 10.2 数据装载脚本 第9章 广…...
计算机毕业设计 家电销售展示平台 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...
C# 根据MySQL数据库中数据,批量删除OSS上的垃圾文件
protected void btndeleteTask_Click(object sender, EventArgs e){//获取标识为已删除数据,一次加载500条int countlocks _goodsItemsApplication.CountAllNeedExecuteTask();int totalPagelocks (countlocks 500 - 1) / 500;//分批次处理for (int curentpage …...
Vue3+Element-plus+setup使用vuemap/vue-amap实现高德地图API相关操作
首先要下载依赖并且引入 npm安装 // 安装核心库 npm install vuemap/vue-amap --save// 安装loca库 npm install vuemap/vue-amap-loca --save// 安装扩展库 npm install vuemap/vue-amap-extra --save cdn <script src"https://cdn.jsdelivr.net/npm/vuemap/vue-a…...
Windows配置开机直达桌面并跳过锁屏登录界面在 Windows 10 中添加在启动时自动运行的应用
目录 Win10开机直达桌面并跳过锁屏登录界面修改组策略修改注册表跳过登录界面 在 Windows 10 中添加在启动时自动运行的应用设置系统级别服务一、Windows下使用sc将应用程序设置为系统服务1. 什么是sc命令?2. sc命令的基本语法3. 创建Windows服务的步骤与示例创建服…...
pythonUI自动化007::pytest的组成以及运行
pytest组成: 测试模块:以“test”开头或结尾的py文件 测试用例:在测试模块里或测试类里,名称符合test_xxx函数或者示例函数。 测试类:测试模块里面命名符合Test_xxx的类 函数级: import pytestclass Test…...
开放式耳机哪个品牌好用又实惠?五大口碑精品分享
如今开放式耳机市场日益火爆,不少知名品牌都在对产品进行升级迭代,那么如何在一众品牌型号中选择到自己最满意的那一款呢?开放式耳机哪个品牌好用又实惠?这就需要更专业的选购攻略,因此笔者专门整理出了专业机构的开放…...
代码随想录算法训练营day39||动态规划07:多重背包+打家劫舍
多重背包理论 描述: 有N种物品和一个容量为V 的背包。 第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。 求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。 本质: …...
WebSocket革新:用PHP实现实时Web通信
标题:WebSocket革新:用PHP实现实时Web通信 在现代Web应用中,实时通信是一个不可或缺的功能。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,它允许服务器主动向客户端推送数据,极大地简化了客户端和服务器之…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
比特币:固若金汤的数字堡垒与它的四道防线
第一道防线:机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”(Hashing)就是一种军事级的加密术(SHA-256),能将信函内容(交易细节…...
如何让非 TCP/IP 协议驱动屏蔽 IPv4/IPv6 和 ARP 报文?
——从硬件过滤到协议栈隔离的完整指南 引言 在现代网络开发中,许多场景需要定制化网络协议(如工业控制、高性能计算),此时需确保驱动仅处理特定协议,避免被标准协议(如 IPv4/IPv6/ARP)干扰。本文基于 Linux 内核驱动的实现,探讨如何通过硬件过滤、驱动层拦截和协议栈…...
n8n:解锁自动化工作流的无限可能
在当今快节奏的数字时代,无论是企业还是个人,都渴望提高工作效率,减少重复性任务的繁琐操作。而 n8n,这个强大的开源自动化工具,就像一位智能的数字助手,悄然走进了许多人的工作和生活,成为提升…...
React 样式方案与状态方案初探
React 本身只提供了基础 UI 层开发范式,其他特性的支持需要借助相关社区方案实现。本文将介绍 React 应用体系中样式方案与状态方案的主流选择,帮助开发者根据项目需求做出合适的选择。 1. React 样式方案 1.1. 内联样式 (Inline Styles) 通过 style …...
【Redis】Redis 的持久化策略
目录 一、RDB 定期备份 1.2 触发方式 1.2.1 手动触发 1.2.2.1 自动触发 RDB 持久化机制的场景 1.2.2.2 检查是否触发 1.2.2.3 线上运维配置 1.3 检索工具 1.4 RDB 备份实现原理 1.5 禁用 RDB 快照 1.6 RDB 优缺点分析 二、AOF 实时备份 2.1 配置文件解析 2.2 开启…...
