【Spring】Bean 的作用域和生命周期

本文详细介绍了Spring框架中Bean的作用域(单例、原型、请求、会话、全局和WebSocket)及其设置方法,以及Bean的生命周期(实例化、属性设置、初始化和销毁)及其顺序。通过实例演示了如何避免Bean作用域带来的干扰和确保正确的行为模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你:
📕 JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等
📗 Java数据结构: 顺序表, 链表, 堆, 二叉树, 二叉搜索树, 哈希表等
📘 JavaEE初阶: 多线程, 网络编程, TCP/IP协议, HTTP协议, Tomcat, Servlet, Linux, JVM等(正在持续更新)

Bean 的作用域和生命周期是面试中很常见的问题, 就连字节, 百度等大厂也常考, 本文就介绍 Bean 的六种作用域, 和生命周期( 5 步执行流程)
在这里插入图片描述


提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之处欢迎批评指点~ 废话不多说,直接上干货!


一、关于 Bean 的作用域问题引入

  • 定义一个 User 类(@Component注解), 作为公共的 Bean, 此类中仅需设置一个成员属性 name, 并给定值, 再提供 setter() 和 toString() 方法即可 :
    在这里插入图片描述

  • 定义 UserComponent 类(@Component注解), 把上面的 User(公共Bean) 注入到当前类, 定义一个 run() 方法调用 User 类提供的 setter() 方法, 修改公共 Bean 的 name 属性
    在这里插入图片描述

  • 定义 UserComponent2 类(@Component注解), 不对公共Bean 进行修改, 只是访问它, 查看它的 name 是什么
    在这里插入图片描述

  • 在启动类中获取 UserComponent 和 UserComponent2 这两个 Bean, 分别调用 run() 方法
    在这里插入图片描述

我们期望 : 对于公共的 Bean , UserComponent 在使用时修改了它, 而 UserComponent2 在使用公共 Bean 时, 不被 UserComponent 的行为所干扰
也就是说 : 原本 Bean 中的 name = “喜羊羊”, UserComponent 修改成了"沸羊羊", 我们希望 UserComponent2 访问公共 Bean 时看到的还是"喜羊羊"

  • 观察结果 :
    在这里插入图片描述

为什么公共的 Bean 中的值被修改了? 那是不是意味着整个项目里, 一个 Bean 不应该被某个类访问并修改?

产生这种现象就是 Bean 的作用域导致的


二、Bean 的作用域

1, 什么是 Bean 的作用域

Bean 的作用域指的是Bean在整个 Spring 框架中的某个行为模式,比如 singleton 单例作用域表示 Bean 在整个 Spring 中只有一份,是全局共享的,当有一个用户修改了这个对象后,其他用户获取的就是这个修改后的对象

Bean 的作用域有 6 种:

  1. singleton:单例作用域

  2. prototype:原型作用域(也叫多例作用域)

  3. request:请求作用域

  4. session:会话作用域

  5. application:全局作用域

  6. websocket:HTTP WebSocket 作用域


2, Bean 的六种作用域

1, singleton:单例作用域

  • 该作用域下的 Bean 在 IoC 容器中只存在一个实例:获取 Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注⼊)都是同一对象
  • 这是 Spring 默认的作用域
  • 通常是无状态的 Bean 使用的作用域 (无状态表示 Bean 对象的属性状态不需要修改)

2, prototype:原型作用域

  • 原型作用域也叫作多例作用域, 每次从 Spring 中获取 Bean 对象, 都会创建一份新的实例, @Autowired, @Resource 注入的对象以及 context 上下文 getBean 拿到的都是不同的 bean 对象
  • 通常是有状态的 Bean 使用的作用域 (有状态表示 Bean 对象的属性需要被修改)

3, request:请求作用域

  • 仅存在于 Spring MVC 中
  • 每一次 HTTP 请求都会创建新的实例, 类似于 prototype
  • 一次 HTTP 的请求和响应共享一个 bean

4, session:会话作用域

  • 仅存在于 Spring MVC 中
  • 在一个 HTTP session 中, 定义一个 Bean 实例

5, application:全局作用域

  • 仅存在于 Spring MVC 中
  • 在⼀个http servlet Context中,定义一个 Bean实例

6, websocket:HTTP WebSocket 作用域

  • 仅存在于 Spring MVC 中
  • 在一个 HTTP WebSocket 的生命周期中,定义一个 Bean 实例, WebSocket 的每次会话中,保存了一个 Map 结构的头信息,将用来包裹客户端消息头, 第一次初始化后,直到 WebSocket 结束都是同一个 Bean

3, 设置 Bean 的作用域(解决开篇的问题)

了解了 Bean 作用域, 我们知道, 在开篇引入的示例中, 由于 Bean 的默认作用域是 singleton, 如果改成 prototype , 那么在 UserComponent 和 UserComponent2 中, 注入 Bean 时就会创建一份新的实例, 哪怕有一万个类都是用这个 Bean 也不会互相干扰

声明 Bean 的作用域 : 使用 @Scope 注解

  • 使用方式1 : @Scope(“prototype”)
    在这里插入图片描述
    在这里插入图片描述

  • 使用方式2 : @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    在这里插入图片描述
    在这里插入图片描述

@Scope 可以加在类上, 配合类注解(@Controller、@Service、@Repository、@Component、@Configuration )使用
也可以加在方法上配合方法注解(@Bean)使用


三、Bean 的生命周期

所谓的生命周期指的是一个对象从诞生到销毁的整个生命过程, 我们把这个过程就叫做一个对象的生命周期, Bean 的生命周期就是 Bean 从诞生到销毁的过程

Bean 的生命周期基本分为以下 5 步 :

  1. 实例化 Bean (开辟内存空间)

  2. 设置属性( Bean 注入)

  3. 初始化 Bean
    3.1, 执行实现了各种 Aware (通知)接口的方法
    3.2, 执行初始化的前置方法
    3.3, 执行初始化方法
    3.3, 执行初始化的后置方法

  4. 使用 Bean

  5. 销毁 Bean

在这里插入图片描述

Bean 的销毁是由容器管理的, 不归 JVM 的垃圾回收机制管理

第二步和第三步的顺序能调换吗?(为什么要先注入再初始化?)
答案是否定的, 在第三步(初始化 Bean )时, 会执行各种各样的方法, 在这些方法中, 如果使用注入进来的 Bean, 但此时如果还没有把 Bean 注入进来, 还怎么使用? 可想而知会产生异常, 所以是先注入 Bean , 再进行初始化 Bean


总结

以上就是本篇的所有内容了, 如果本篇对你有帮助,请点赞收藏支持一下,小手一抖就是对作者莫大的鼓励啦😋😋😋~


上山总比下山辛苦
下篇文章见

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灵魂相契的树

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值