Spring中Bean的作用域深入剖析与技术实践
前言
Spring框架作为Java企业级应用开发中的中流砥柱,提供了强大的依赖注入(DI)和面向切面编程(AOP)等功能。在Spring框架中,Bean的作用域(Scope)是一个非常重要的概念,它决定了Bean实例的生命周期和共享方式。本文将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring中Bean的作用域,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
一、Bean作用域概述
在Spring框架中,Bean的作用域决定了Bean实例在Spring IoC容器中的创建方式、生命周期以及共享方式。Spring支持多种作用域,每种作用域都有其特定的应用场景和生命周期管理策略。
1.1 作用域类型
Spring支持以下五种作用域:
- singleton:默认作用域,Spring IoC容器中仅存在一个Bean实例,所有对该Bean的请求都将返回同一个实例。
- prototype:每次请求Bean时都会创建一个新的实例,适用于有状态的Bean或需要频繁创建新实例的场景。
- request:每次HTTP请求都会创建一个新的Bean实例,仅在当前HTTP请求内有效,适用于Web应用程序。
- session:每次HTTP会话都会创建一个新的Bean实例,仅在当前HTTP会话内有效,适用于Web应用程序。
- globalSession:类似于session作用域,但仅在Portlet应用程序中使用,用于跨Portlet的会话共享。
1.2 作用域的选择原则
在选择Bean的作用域时,需要考虑以下几个因素:
- 性能:singleton作用域可以减少对象创建的开销,但需要注意线程安全问题;prototype作用域则每次都会创建新实例,可能导致性能下降。
- 状态管理:无状态的Bean适合使用singleton作用域,而有状态的Bean则应该使用prototype作用域或其他请求/会话作用域。
- 应用场景:根据Bean的具体应用场景选择合适的作用域,例如Web应用程序中常用request和session作用域来管理用户的会话状态。
二、Bean作用域的功能点
2.1 Singleton作用域
Singleton作用域是Spring的默认作用域,它保证了在整个应用程序中只有一个Bean实例。这种作用域适用于无状态的Bean,如服务类、工具类等。由于只有一个实例,因此需要注意线程安全问题。
示例代码
java复制代码
@Service
public class MyService {
// 业务逻辑代码
}
在上面的示例中,MyService
类被标记为@Service
,Spring会自动将其注册为singleton作用域的Bean。
2.2 Prototype作用域
Prototype作用域每次请求都会创建一个新的Bean实例。这种作用域适用于有状态的Bean或需要频繁创建新实例的场景。
示例代码
java复制代码
@Component
@Scope("prototype")
public class MyPrototypeBean {
// 有状态的属性
private String state;
public void setState(String state) {
this.state = state;}
public String getState() {
return state;}
}
在上面的示例中,MyPrototypeBean
类被标记为@Component
和@Scope("prototype")
,表示每次请求都会创建一个新的实例。
2.3 Request作用域
Request作用域每次HTTP请求都会创建一个新的Bean实例,仅在当前HTTP请求内有效。这种作用域适用于Web应用程序中需要管理用户请求状态的场景。
示例代码
java复制代码
@Component
@Scope("request")
public class MyRequestBean {
// 请求相关的属性
private String requestData;
public void setRequestData(String requestData) {
this.requestData = requestData;}
public String getRequestData() {
return requestData;}
}
在上面的示例中,MyRequestBean
类被标记为@Component
和@Scope("request")
,表示每次HTTP请求都会创建一个新的实例。
2.4 Session作用域
Session作用域每次HTTP会话都会创建一个新的Bean实例,仅在当前HTTP会话内有效。这种作用域适用于Web应用程序中需要管理用户会话状态的场景。
示例代码
java复制代码
@Component
@Scope("session")
public class MySessionBean {
// 会话相关的属性
private String sessionData;
public void setSessionData(String sessionData) {
this.sessionData = sessionData;}
public String getSessionData() {
return sessionData;}
}
在上面的示例中,MySessionBean
类被标记为@Component
和@Scope("session")
,表示每次HTTP会话都会创建一个新的实例。
2.5 GlobalSession作用域
GlobalSession作用域类似于session作用域,但仅在Portlet应用程序中使用,用于跨Portlet的会话共享。由于Portlet应用相对较少,因此这种作用域的使用场景也比较有限。
三、Bean作用域的背景
3.1 Spring框架的发展
Spring框架自2002年发布以来,经历了多个版本的迭代和更新。随着Java EE技术的发展和Web应用程序的普及,Spring框架逐渐成为了Java企业级应用开发的首选框架之一。在这个过程中,Bean作用域的概念也逐渐丰富和完善,以适应不同应用场景的需求。
3.2 Web应用程序的需求
在Web应用程序中,用户的状态管理是一个非常重要的问题。为了解决这个问题,Spring框架引入了request和session作用域,使得开发者可以方便地在Web应用程序中管理用户的请求状态和会话状态。随着Web技术的发展和Portlet应用的出现,Spring框架又引入了globalSession作用域来支持跨Portlet的会话共享。
四、Bean作用域的业务点
4.1 数据共享与隔离
不同的作用域决定了Bean实例的共享方式和生命周期。例如,singleton作用域的Bean在整个应用程序中只有一个实例,适用于全局共享的数据;而prototype作用域的Bean每次请求都会创建一个新的实例,适用于需要隔离数据的场景。在Web应用程序中,request和session作用域的Bean则分别用于管理请求级别和会话级别的数据。
4.2 性能优化
Bean作用域的选择对应用程序的性能有很大影响。例如,singleton作用域的Bean可以减少对象创建的开销,提高应用程序的性能;而prototype作用域的Bean则每次请求都会创建新实例,可能导致性能下降。因此,在选择Bean作用域时需要根据具体应用场景进行权衡和优化。
4.3 线程安全
对于singleton作用域的Bean来说,由于整个应用程序中只有一个实例,因此需要注意线程安全问题。如果Bean中存在可变的成员变量并且多个线程同时访问这些变量,就可能导致数据不一致或线程安全问题。为了避免这种问题,可以通过减少可变状态、使用不可变对象或同步代码块等方式来保证线程安全。
五、Bean作用域的底层原理
5.1 Bean的创建过程
在Spring框架中,Bean的创建过程可以分为以下几个步骤:
- 解析配置:Spring容器在启动时会解析配置文件或注解,获取Bean的定义信息。
- 实例化Bean:根据Bean的定义信息创建Bean的实例。对于singleton作用域的Bean来说,容器会在启动时就创建实例;而对于prototype作用域的Bean来说,则会在每次请求时创建实例。
- 设置属性:将Bean的依赖注入到其属性中。
- 初始化Bean:调用Bean的初始化方法(如果有的话)。
5.2 Bean的存储与获取
在Spring框架中,Bean实例被存储在IoC容器中。对于singleton作用域的Bean来说,容器会将其存储在一个单例缓存中;而对于prototype作用域的Bean来说,则不会存储在缓存中,每次请求时都会重新创建实例。当需要获取Bean实例时,容器会根据Bean的作用域从相应的存储位置中获取实例。
5.3 Bean的生命周期管理
不同的作用域决定了Bean实例的生命周期管理方式。对于singleton作用域的Bean来说,其生命周期与Spring容器相同,容器启动时创建实例,容器关闭时销毁实例;而对于prototype作用域的Bean来说,其生命周期则由开发者自行管理,每次请求时创建实例,使用完毕后由开发者负责销毁实例(实际上在Java中由垃圾回收器负责销毁)。对于request和session作用域的Bean来说,其生命周期则分别与HTTP请求和HTTP会话的生命周期相同。
六、实践案例与优缺点分析
6.1 实践案例一:单例Bean的管理
场景描述
在一个在线商城系统中,有一个商品服务类ProductService
用于处理商品的增删改查操作。由于商品服务类的实例在整个应用程序中只需要一个即可满足需求,因此可以选择将其配置为singleton作用域的Bean。
实现代码
java复制代码
@Service
public class ProductService {
// 商品服务相关的业务逻辑代码
}
在上面的代码中,ProductService
类被标记为@Service
,Spring会自动将其注册为singleton作用域的Bean。
优缺点分析
优点:
- 性能高:由于整个应用程序中只有一个实例,减少了对象创建的开销。
- 状态共享:所有请求共享同一个实例,方便数据共享。
缺点:
- 线程安全问题:如果有多个线程同时访问该实例并修改其状态,可能会导致数据不一致或线程安全问题。
- 灵活性较低:所有请求都复用同一个实例,不适合需要独立实例的场景。
6.2 实践案例二:原型Bean的管理
场景描述
在一个在线支付系统中,每次用户发起支付请求时都需要创建一个新的支付订单对象PaymentOrder
。由于每个支付订单都是独立的且需要保持状态信息(如订单金额、支付状态等),因此可以选择将其配置为prototype作用域的Bean。
实现代码
java复制代码
@Component
@Scope("prototype")
public class PaymentOrder {
// 支付订单相关的属性
private double amount;
private String status;
// 省略getter和setter方法
}
在上面的代码中,PaymentOrder
类被标记为@Component
和@Scope("prototype")
,表示每次请求都会创建一个新的实例。
优缺点分析
优点:
- 线程安全:每次请求都会创建一个新的实例,避免了多线程间的数据竞争问题。
- 灵活性高:适合需要独立实例或有状态Bean的场景。
缺点:
- 性能开销:频繁创建和销毁实例可能导致性能下降。
- 生命周期管理:需要开发者手动管理Bean的创建和销毁(实际上在Java中由垃圾回收器负责销毁),增加了编程复杂度。
6.3 实践案例三:请求作用域Bean的管理
场景描述
在一个Web应用程序中,需要记录用户的登录信息以便在请求处理过程中使用。由于登录信息只需要在当前HTTP请求内有效,因此可以选择将其配置为request作用域的Bean。
实现代码
java复制代码
@Component
@Scope("request")
public class UserLoginInfo {
// 用户登录信息相关的属性
private String username;
private String sessionId;
// 省略getter和setter方法
}
在上面的代码中,UserLoginInfo
类被标记为@Component
和@Scope("request")
,表示每次HTTP请求都会创建一个新的实例。
优缺点分析
优点:
- 线程安全:每个HTTP请求都会创建一个新的实例,天然地隔离了请求之间的状态。
- 资源节约:请求结束后自动销毁实例,避免了不必要的资源占用。
缺点:
- 适用范围限制:仅适用于Web应用程序且需要特定的Servlet容器支持。
- 生命周期短:仅在请求生命周期内有效,对于跨请求的数据管理不适用。
6.4 实践案例四:会话作用域Bean的管理
场景描述
在一个购物车系统中,需要记录用户的购物车信息以便在用户会话期间内持续有效。由于购物车信息需要在整个HTTP会话期间内有效且需要保持状态信息(如商品列表、总价等),因此可以选择将其配置为session作用域的Bean。
实现代码
java复制代码
@Component
@Scope("session")
public class ShoppingCart {
// 购物车相关的属性
private List<Product> products = new ArrayList<>();
private double totalPrice;
// 省略getter和setter方法以及业务逻辑代码
}
在上面的代码中,ShoppingCart
类被标记为@Component
和@Scope("session")
,表示每个HTTP会话都会创建一个新的实例。
优缺点分析
优点:
- 持久化会话状态:每个用户会话创建一个实例,可以用来保存会话级别的数据。
- 线程安全:每个用户拥有独立的实例避免了并发冲突。
缺点:
- 资源消耗:长时间的会话可能导致内存占用增加。
- 适用范围限制:同样局限于Web应用且依赖于会话管理机制。
七、总结与展望
通过本文的深入剖析和技术实践展示,我们可以对Spring中Bean的作用域有一个全新的认识。不同的作用域决定了Bean实例的创建方式、生命周期以及共享方式,对于优化应用性能、管理资源和确保线程安全至关重要。在未来的发展中,随着Java EE技术和Web应用程序的不断演进,Spring框架中的Bean作用域概念也将继续丰富和完善以适应更多应用场景的需求。作为开发者我们需要不断学习和掌握这些新技术以提升自己的竞争力并为企业创造更大的价值。
相关文章:
Spring中Bean的作用域深入剖析与技术实践
前言 Spring框架作为Java企业级应用开发中的中流砥柱,提供了强大的依赖注入(DI)和面向切面编程(AOP)等功能。在Spring框架中,Bean的作用域(Scope)是一个非常重要的概念,…...
Python爬虫实战:抓取拼多多商品详情数据(基于pdd.item_get接口)
在当前的电商市场中,拼多多以其独特的拼团模式和优惠价格吸引了大量用户,成为继淘宝、京东之后的又一大电商平台。对于数据分析和市场研究者来说,获取拼多多的商品详情数据显得尤为重要。本文将介绍如何使用Python爬虫技术,通过调…...
工具类-列表请求工具 useList
useList 用于列表请求的基于 vue 3 的 hooks,接收请求函数、请求参数等数据,自动生成请求请求函数,分页信息等 本文有涉及到 http 请求工具和接口返回格式的内容: http 工具:一个基于 axios 封装的请求工具Response…...
Scala中的正则表达式01
规则类型具体规则示例说明单字符大多数字符匹配自身正则表达式 abc,文本 abca 匹配 a,b 匹配 b,c 匹配 c方括号 [ ][ ] 定义字符集,匹配其一[abc],文本 a、b 或 c[abc] 匹配 a、b 或者 c排除字符集 [^ ][^ ] 开头加 ^&…...

基于SpringBoot的养老院管理系统的设计与实现
一、前言 随着人口老龄化的加剧,养老院作为老年人养老的重要场所,其管理的高效性和科学性显得尤为重要。传统的养老院管理方式多依赖人工操作,存在信息记录不及时、不准确,管理流程繁琐,资源调配困难等问题。利用信息技…...
Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
本篇文章详细给大家介绍Ansible变量,变量适合管理剧本中每个项目的动态值,或是某些值在多个地方重复使用,如果将此值设置为变量再在其他地方调用会方便许多。会用变量,才算真正会用Ansible,话不多说,直接开…...
面向对象系统的分析和设计
来源:《设计模式精解-GOF23种设计模式解析》 作者:k_eckel k_eckels mindview - 博客园 (cnblogs.com) --------- 面向对象系统的分析和设计实际上追求的就是两点: (1)高内聚 (2)低耦合 …...

Vue 提供了Transition,可以帮助你制作基于状态变化的过渡和动画
官方文档:https://cn.vuejs.org/guide/built-ins/transition.html Transition Vue 提供了两个内置组件,可以帮助你制作基于状态变化的过渡和动画: <Transition> 会在一个元素或组件进入和离开 DOM 时应用动画。本章节会介绍如何使用…...

视频编辑技术:一键生成混剪视频的AI技术应用
随着视频内容的爆炸式增长,视频编辑技术也在不断进步。本文将探讨如何利用AI技术,实现一键生成混剪视频,并自动添加配音和字幕,以提高视频编辑的效率和质量。 AI技术在视频编辑中的应用 AI技术在视频编辑领域的应用越来越广泛&am…...
Android11 MTK 开机默认启动热点
1、需求:开机后不锁屏,默认打开热点,且长时间没有设备连接热点时保证热点也是打开的。 2、开机后不锁屏: 路径:vendor/mediatek/proprietary/packages/apps/SettingsProvider/res/values/defaults.xml<bool name&q…...

Vue Web开发(二)
1. 项目搭建 1.1. 首页架子搭建 使用Element ui中的Container布局容器,选择倒数第二个样式,将代码复制到Home.vue。 1.1.1.下载less (1)下载less样式 npm i less (2)下载less编辑解析器 npm i less…...

Linux-实用操作
文章目录 一. 各类实用小技巧(快捷键)1. ctrl c 强制停止2. ctrl d 退出登出3. history 查看历史命令4. !命令前缀,自动匹配上一个命令5. ctrl r,搜索历史命令6. ctrl a | e,光标移动到命令开始或结束7. ctrl ← | →,左右跳…...

Elasticsearch:使用 Elastic APM 监控 Android 应用程序
一、前言 人们通过私人和专业的移动应用程序在智能手机上处理越来越多的事情。 拥有成千上万甚至数百万的用户,确保出色的性能和可靠性是移动应用程序和相关后端服务的提供商和运营商面临的主要挑战。 了解移动应用程序的行为、崩溃的发生和类型、响应时间慢的根本…...
Go的简单问题问答
基础问题回答 Go 的主要特点是什么? 简洁:语法简化,减少复杂性。并发:内置 Goroutine 和 Channel,支持轻量级并发。静态类型:强类型语言,编译时检查错误。跨平台:编译生成独立的二进…...

【攻防实验】溯源与取证分析实验
溯源与取证分析实验 溯源取证分析作为网络攻防过程中重要环节,准确找到攻击者的入侵线索(尤其是攻击突破口、攻击IP地址、域名、工具等信息),对于企业或者团队安全运营团队来说都是必备技能。常规攻击取证过程中往往会结合流量、Web访问日志、终端系统或…...
THREE.js 入门(一)xyz坐标系
一、坐标系概念 在 three.js 中,相机的默认朝向是沿着 Z 轴的负方向。也就是说,默认情况下,相机会沿着 Z 轴的负方向“看”到场景中的对象,而 X 轴和 Y 轴分别对应水平方向和垂直方向。换句话说,相机的默认位置是 (0,…...

AUTOSAR CP中基于通信模块(COM)的Transformer-R24的规范导读
该文档是关于 AUTOSAR CP中基于通信模块(COM)的Transformer的规范说明,主要内容包括引言、相关文档、约束与假设、功能规范、API 规范、配置规范等,旨在为汽车电子系统开发中基于 COM 的Transformer提供全面的技术规范和指导。 一…...
ubuntu20.04安装anygrasp_sdk
ubuntu20.04安装anygrasp_sdk采坑记录 安装ME的教程看上一篇,现在来看anygrasp安装问题grasp_detection、grasp_trackinglicense申请demo文件的运行注意的地方到这以为大功告成了,然后出现了一个numpy版本不匹配问题最后还有一个问题就是修改demo.sh,不然没法可视化结果展示安…...

Spring完整知识点二
Spring注解开发 Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,它能够代替xml配置文件,可以简化配置,提高开发效率Spring注解根据出现时间分类 Spring原始注解…...
GESP三级集训——课堂笔记(部分)
进制转换(二进制、十进制、八进制、十六进制等) 十进制(逢十进一)——Decimal 十进制是我们生活中最常见的进制,如“1”“23”“891”等: 进位过程如下:{1,2,3,4,5,6,7,8,9}{10,11,12,13,14,…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
前端工具库lodash与lodash-es区别详解
lodash 和 lodash-es 是同一工具库的两个不同版本,核心功能完全一致,主要区别在于模块化格式和优化方式,适合不同的开发环境。以下是详细对比: 1. 模块化格式 lodash 使用 CommonJS 模块格式(require/module.exports&a…...
6.计算机网络核心知识点精要手册
计算机网络核心知识点精要手册 1.协议基础篇 网络协议三要素 语法:数据与控制信息的结构或格式,如同语言中的语法规则语义:控制信息的具体含义和响应方式,规定通信双方"说什么"同步:事件执行的顺序与时序…...

【Vue】scoped+组件通信+props校验
【scoped作用及原理】 【作用】 默认写在组件中style的样式会全局生效, 因此很容易造成多个组件之间的样式冲突问题 故而可以给组件加上scoped 属性, 令样式只作用于当前组件的标签 作用:防止不同vue组件样式污染 【原理】 给组件加上scoped 属性后…...