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

Bean作用域和生命周期

Bean作用域和生命周期


文章目录

  • Bean作用域和生命周期
  • 通过一个案例来看Bean作用域问题
    • 案例背景
    • 代码示例
    • 执行结果
    • 原因分析
  • 作用域定义
  • Bean的6种作用域
    • Bean的作用域
    • 单例作用域(singleton)和全局作用域(application)区别
  • Bean原理分析
    • Bean执行流程
    • Bean 生命周期
    • 初始化和设置的区别
      • 操作内容
      • 执行顺序
      • 目的和作用
      • 对Bean状态的影响


通过一个案例来看Bean作用域问题

案例背景

有一个公共 Bean 供 A 用户和 B 用户使用,A 用户修改了公共 Bean 的数据,导致 B 用户使用时出现预期外逻辑错误,预期公共 Bean 在各自类中修改不影响其他类。

代码示例

  • 公共 Bean
@Component
public class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("Java"); return user;}
}
  • A 用户使用(修改操作)
@Controller
public class BeanScopesController {@Autowiredprivate User user1;public User getUser1() {User user = user1;System.out.println("Bean 原 Name: " + user.getName());user.setName("悟空"); return user;}
}
  • B 用户使用
@Controller
public class BeanScopesController2 {@Autowiredprivate User user1;public User getUser1() {User user = user1;return user;}
}
  • 测试类
public class BeanScopesTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BeanScopesController beanScopesController = context.getBean(BeanScopesController.class);System.out.println("A 对象修改之后 Name: " + beanScopesController.getUser1().toString());BeanScopesController2 beanScopesController2 = context.getBean(BeanScopesController2.class);System.out.println("B 对象读取到的 Name: " + beanScopesController2.getUser1().toString());}
}

执行结果

A 用户修改后,B 用户读取到的 Bean 名称也变为了“悟空”

原因分析

Bean 默认是单例状态(singleton),所有人使用的都是同一个对象,所以 A 用户的修改会影响 B 用户对 Bean 的使用

作用域定义

  • 在程序中,变量的可用范围叫做作用域,或者源代码中定义变量的某个区域叫做这个变量的作用域
  • 在 Spring 框架中,Bean 的作用域(Scope)和生命周期是核心概念,它们决定了 Bean 的创建、存在时间和销毁方式

Bean的6种作用域

Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域。Spring 有 6 种作用域,最后四种是基于 Spring MVC 生效的:

  1. singleton:单例作用域
  2. prototype:原型作用域(多例作用域)
  3. request:请求作用域
  4. session:回话作用域
  5. application:全局作用域
  6. websocket:HTTP WebSocket 作用域

注意后 4 种状态是 Spring MVC 中的值,在普通的 Spring 项目中只有前两种。
在Spring框架中,Bean的作用域(Scope)和生命周期是核心概念,它们决定了Bean的创建、存在时间和销毁方式。

Bean的作用域

作用域定义了Bean实例的创建方式和生命周期范围。Spring提供了以下几种常用作用域:

  1. singleton(单例,默认)

    • 整个应用中只存在一个Bean实例。
    • 当容器初始化时创建(可通过lazy-init="true"延迟到首次使用时创建)。
    • 适用场景:无状态Bean(如工具类、服务层组件)。
  2. prototype(原型)

    • 每次从容器中获取Bean时,都会创建一个新实例。
    • 容器仅负责创建,不管理销毁(需手动处理资源释放)。
    • 适用场景:有状态Bean(如请求参数对象、会话相关对象)。
  3. request(请求,Web环境)

    • 每个HTTP请求创建一个新实例,请求结束后销毁。
    • 适用场景:存储请求级别的数据(如Controller中的请求参数)。
  4. session(会话,Web环境)

    • 每个用户会话(Session)创建一个实例,会话结束后销毁。
    • 适用场景:存储用户会话信息(如登录状态)。
  5. application(应用,Web环境)

    • 整个Web应用生命周期内只存在一个实例,与singleton类似,但作用域为ServletContext。
  6. websocket(WebSocket,Web环境)

    • 每个WebSocket连接创建一个实例,连接关闭后销毁。

单例作用域(singleton)和全局作用域(application)区别

  • singleton 是 Spring Core 的作用域;application 是 Spring Web 中的作用域

Bean原理分析

  • 现在,我们来看一下Bean执行原理和生命周期总结

Bean执行流程

Bean 执行流程(Spring 执行流程):启动 Spring 容器 -> 实例化 Bean(分配内存空间,从无到有)-> Bean 注册到 Spring 中(存操作)-> 将 Bean 装配到需要的类中(取操作)

Bean 生命周期

所谓的生命周期指的是一个对象从诞生到销毁的整个生命过程,我们把这个过程就叫做一个对象的生命周期。
Bean 的生命周期分为以下 5 大部分:

  1. 实例化 Bean(为 Bean 分配内存空间)
  2. 设置属性(Bean 注入和装配)
  3. Bean 初始化
    • 实现了各种 Aware 通知的方法,如 BeanNameAware、BeanFactoryAware、ApplicationContextAware 的接口方法;
    • 执行 BeanPostProcessor 初始化前置方法;
    • 执行 @PostConstruct 初始化方法,依赖注入操作之后被执行;
    • 执行自己指定的 init - method 方法(如果有指定的话);
    • 执行 BeanPostProcessor 初始化后置方法。
  4. 使用 Bean
  5. 销毁 Bean
    销毁容器的各种方法,如 @PreDestroy、DisposableBean 接口方法、destroy - method。

执行流程如下图所示:
在这里插入图片描述

初始化和设置的区别

在Bean生命周期中,“设置属性” 和 “初始化” 是两个不同阶段,它们存在多方面区别:

操作内容

  • 设置属性:主要涉及依赖注入,即给Bean的属性赋值。Spring 通过诸如@Autowired@Value 等注解,或者 XML 配置中的<property>标签 ,将其他Bean实例、配置值等注入到当前Bean对应的属性中 。例如,一个UserService需要依赖UserRepository,Spring会在设置属性阶段将UserRepository的实例注入到UserService中对应的userRepository属性上
  • 初始化:是在设置属性完成后,对Bean进行进一步的配置和准备工作,使其达到可用状态。这个阶段会执行一些特定的初始化方法,比如实现InitializingBean接口的afterPropertiesSet方法、带有@PostConstruct注解的方法,以及在配置文件中指定的init-method方法 。在这些方法里,通常会进行资源的加载(如加载数据库连接池配置、读取配置文件等)、状态的检查和初始化等操作

执行顺序

在Bean生命周期中,先执行设置属性操作,完成依赖注入后,才会进入初始化阶段。只有当所有需要注入的属性都正确赋值后,才能确保初始化方法执行时,Bean处于一个相对完整且可操作的状态,避免因属性未赋值而引发的空指针等异常

目的和作用

  • 设置属性:侧重于建立Bean之间的依赖关系,解决Bean运行时所需要的外部资源注入问题,让Bean在创建后能够获取到执行其功能所依赖的其他组件。
  • 初始化:目的是让Bean为实际的使用做好准备,确保Bean的内部状态和外部资源都处于可用状态,从而保证Bean在被应用程序调用时能够正确、稳定地提供服务

对Bean状态的影响

  • 设置属性:操作完成后,Bean的属性被赋值,但此时Bean可能还没有完全准备好执行其核心业务逻辑。例如,一个包含数据库操作的服务Bean,虽然注入了数据库操作的DAO组件,但数据库连接等相关资源可能还未初始化。
  • 初始化:完成后,Bean处于就绪状态,可以被应用程序安全地调用以执行其预定功能。比如上述数据库服务Bean,在初始化阶段完成数据库连接池的初始化等操作后,就可以进行数据库的增删改查操作了。
http://www.xdnf.cn/news/1466623.html

相关文章:

  • Golang中的context包介绍及源码阅读
  • 谙流 ASK 技术解析(一):秒级扩容
  • Android,jetpack Compose模仿QQ侧边栏
  • 华为云昇腾云服务
  • 数据安全成焦点:基于Hadoop+Spark的信用卡诈骗分析系统实战教程
  • 为什么外网主机可以telnet通内网nginx端口,但是http请求失败?
  • Mysql:由逗号分隔的id组成的varchar联表替换成对应文字
  • Tenda AC20路由器缓冲区溢出漏洞分析
  • iOS 抓包工具有哪些?开发、测试与安全场景的实战选择
  • 软考 系统架构设计师系列知识点之杂项集萃(140)
  • 使用 chromedp 高效爬取 Bing 搜索结果
  • 安装Codex(需要用npm)
  • Chrome 插件开发入门指南:从基础到实践
  • 达梦数据守护集群监视器详解与应用指南
  • vsan高可用:确保可访问性、全部数据迁移,两种类型权衡
  • 软件启动时加配置文件 vs 不加配置文件
  • Go 1.25.1基本包
  • 凌力尔特(LINEAR)滤波器LTC1068的二阶滤波器模块设计
  • STM32 USBx Device HID standalone 移植示例 LAT1466
  • 全球企业内容管理ECM市场规模增长趋势与未来机遇解析
  • (4)什么时候引入Seata‘‘
  • 黄金上门回收小程序开发
  • 多路转接介绍及代码实现
  • Rust 基础语法
  • 设计模式笔记
  • 从技术选型到现场配置:DDC 楼宇自控系统全流程落地方案(2025 版)
  • 织信低代码:用更聪明的方式,把想法变成现实!
  • 多语言Qt Linguist
  • 职场礼仪实训室:健康管理专业人才培养的核心支柱与创新实践
  • Springboot实现国际化(MessageSource)