【Spring】Bean的作用域与生命周期详情:请简述Spring的执行流程并分析Bean的生命周期?

news2024/11/8 14:40:39

前言

 我们都知道,Spring框架为开发人员提供了很多便捷,这使得开发人员能够更加专注于应用程序的核心业务逻辑,而不需要花费大量时间和精力在技术细节上。作为一个包含众多工具方法的IoC容器,存取JavaBean是其极为重要的一个环节。本文就对Spring中的Bean的作用域和生命周期详细展开,希望对读者有所帮助~
表情包01


文章目录

  • 前言
  • 1 问题引入
  • 2 Bean 的作用域
    • 2.1 作用域及 Bean 的 6 种作用域
    • 2.2 Spring 中设置作用域
    • 2.3 对案例中的代码进行修改
  • 3 Spring 的执行流程及 Bean 的生命周期
    • 3.1 Spring 的执行流程
    • 3.2 Bean 的生命周期及常见问题
  • 写在最后


1 问题引入

 首先,我们创建一个 Student 类,作为 Bean。通过 StudentBean 类中的 student 配合 @Bean 注解存储 Bean。而后,StudentController 依次先访问 Bean 后对其进行修改。
 最后,通过 StudentAdviceController 再次访问 Bean。观察 StudentAdviceController 访问的 Bean 是否为 StudentController 修改 Bean 之前的值。
案例结构

预期结果: 我们希望 StudentController 对 Bean 的修改并不会影响 StudentAdviceController 对 Bean 的访问,然而事与愿违~

StudentBean

@Component
public class StudentBean {

    @Bean
    public Student student() {
        Student student = new Student();
        student.setName("黄小黄");
        student.setAge(17);
        student.setGender("男");
        return student;
    }
}

StudentController

@Controller
public class StudentController {

    @Autowired
    private Student student;

    public void printStudent() {
        System.out.println("studentController | student: " + student);
        Student s = student;
        s.setName("李大明");
        System.out.println("studentController 修改后: " +student);
    }
}

StudentAdviceController

@Controller
public class StudentAdviceController {

    @Autowired
    private Student student;

    public void printStudent() {
        System.out.println("studentAdviceController | student: " + student);
    }
}

主方法

    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        StudentController studentController =
                context.getBean("studentController", StudentController.class);
        StudentAdviceController studentAdviceController =
                context.getBean("studentAdviceController", StudentAdviceController.class);
        studentController.printStudent();
        studentAdviceController.printStudent();
    }

案例结果
结果1
可见,studentController 对 Bean 修改后,studentAdviceController 访问的是修改后的 Bean,这与预期不符。为了达到预期,我们还需要了解 Spring 中 Bean 的作用域~


2 Bean 的作用域

2.1 作用域及 Bean 的 6 种作用域

何为作用域?

作用域(Scope)是指在编程语言中,定义变量时可以被访问的区域。作用域规定了变量的可见性和访问权限,即定义一个变量或函数时,该变量或函数可以被访问的代码区域。在不同的编程语言中,作用域的具体实现方式可能会略有不同。常见的作用域有全局作用域、函数作用域、块级作用域等。

而我们所说的,Bean 的作⽤域是指 Bean 在 Spring 整个框架中的某种⾏为模式
表情2

Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作⽤域。Spring有 6 种作⽤域,最后四种是基于 Spring MVC ⽣效的。对于前 4 种,需要重点掌握,后两种了解即可~

  1. singleton:单例作⽤域(默认情况) 该作⽤域下的Bean在IoC容器中只存在⼀个实例。通常⽆状态的Bean使⽤该作⽤域。⽆状态表示Bean对象的属性状态不需要更新。
  2. prototype:原型作⽤域(多例作⽤域) 每次对该作⽤域下的Bean的请求都会创建新的实例。即,获取与装配Bean都是新的对象的实例。通常有状态的Bean使⽤该作⽤域。
  3. request:请求作⽤域 每次http请求会创建新的Bean实例,⼀次http的请求和响应的共享Bean。
  4. session:会话作⽤域 在⼀个http session中,定义⼀个Bean实例
    ,是⽤户会话的共享Bean。⽐如:记录⼀个⽤户的登录信息、购物车信息等。
  5. application:全局作⽤域 在⼀个http servlet Context中,定义⼀个Bean实例。Web应⽤的上下⽂信息,⽐如:记录⼀个应⽤的共享信息。
  6. websocket:HTTP WebSocket 作⽤域 在⼀个HTTP WebSocket的⽣命周期中,定义⼀个Bean实例。WebSocket 的每次会话中,保存了⼀个 Map 结构的头信息,将⽤来包裹客户端消息头。第⼀
    次初始化后,直到 WebSocket 结束都是同⼀个Bean。

单例作用域与全局作用域的区别?
单例作用域意味着在容器中,每一个Bean只会被创建一次,并且所有的请求都会返回同一实例。而全局作用域与单例作用域不同,在全局作用域下,Bean 被创建一次后,会在整个应用程序的上下文中共享使用,即每一个请求返回的都是同一个实例。
单例作用域适用于那些状态较少或无状态的 Bean,例如数据操作工具类、服务层、控制器等。而全局作用域适用于需要在多个应用程序和多个线程中共享的 Bean,例如线程池、连接池等。但是由于全局作用域可能会对应用程序的性能产生负面影响,它不应该被滥用。因此,应该在使用全局作用域的时候,慎重考虑后再决定使用。

  • singleton 是 Spring Core 的作⽤域;application 是 Spring Web 中的作⽤域
  • singleton 作⽤于 IoC 的容器,⽽ application 作⽤于 Servlet 容器。

2.2 Spring 中设置作用域

我们可以使用 @Scope 标签来声明 Bean 的作⽤域。
@Scope 标签既可以修饰⽅法也可以修饰类,并且,有两种设置⽅式。这里以设置作用域为 prototype 为例:

  1. 直接设置值:@Scope(“prototype”)
  2. 使⽤枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

2.3 对案例中的代码进行修改

只需要将案例中 Bean 的作用域设置成 prototype 即可~

修改后的 StudentBean 代码如下:

@Component
public class StudentBean {

    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public Student student() {
        Student student = new Student();
        student.setName("黄小黄");
        student.setAge(17);
        student.setGender("男");
        return student;
    }
}

运行结果

至此,运行结果达到预期,即 A 类对 Bean 的修改并不会影响 B 对 Bean 的读取~


3 Spring 的执行流程及 Bean 的生命周期

3.1 Spring 的执行流程

Spring 的执行流程大致如下:
启动 Spring 容器 -> 根据配置完成 Bean 的初始化 -> Bean 注册到 Spring 容器中(存操作) -> 将 Bean 装配到需要的类中(取操作)
Spring执行流程

3.2 Bean 的生命周期及常见问题

生命周期指的是 一个对象从创建到销毁的全过程~,这里所说的 Bean 的生命周期,是指 Bean 从创建到使用再到销毁的完整过程。

  1. 实例化(对应JVM中的“加载”):从无到有,将字节码转换成内存中的对象,只是分配了内存 eg:买了一套毛坯房
  2. 设置属性(Bean注入和装配)eg:购买装修材料(引入外部资源)
  3. 初始化 eg:对房子的装修
    a)各种通知 eg:打电话给各个装修的师傅来施工
    b)初始化的前置工作 eg:师傅达到现场,先勘察环境,制定装修方案,比如测量房子的面积等~
    c)进行初始化工作(两种方式:注解或者xml。使用注解@PostConstruct 初始化、使用(xml) init-method 初始化)eg:两类师傅进行装修:水工、瓦工、电工等。
  4. 使用Bean eg:房子可以住人了
  5. 销毁Bean eg:卖房

具体图示如下:
Bean的生命周期

question1. Bean 实例化与 Bean 初始化的区别?
答: Bean 实例化和 Bean 初始化都是 Spring 容器处理 Bean 生命周期中的不同阶段。

  • Bean 实例化是指 Spring 容器创建 Bean 实例的过程,即根据配置的 Bean 定义、类信息和构造函数等,创建一个 Bean 实例并放入容器中管理。这个过程包括实例化 Bean、调用构造函数、注入依赖等。
  • Bean 初始化是指在 Bean 实例创建完成之后,Spring 容器调用特定的方法对 Bean 进行初始化配置的过程。这些特定的方法可以是自定义的方法,也可以是 Spring 提供的初始化方法,比如:InitializingBean 接口的 afterPropertiesSet() 方法和 @PostConstruct 注解等。在这个阶段,可以为 Bean 配置一些属性、调用一些初始化方法等。

question2. 为什么先设置属性而后再初始化?
答: 在 Bean 的生命周期中,先设置属性再初始化,是因为在 Spring IoC 容器中,Bean 的创建和初始化分为两个阶段,即 Bean 的实例化和属性注入阶段,和 Bean 的初始化阶段。在实例化阶段,Spring IoC 容器会先创建 Bean 的实例对象,但此时 Bean 的属性还未被注入。接着,Spring IoC 容器调用 Bean 的 set 方法注入属性值。当所有属性都被注入后,Spring IoC 容器才会执行 Bean 的初始化方法。因此,先设置属性而后再初始化。


写在最后

本文被 JavaEE编程之路 收录点击订阅专栏 , 持续更新中。
 以上便是本文的全部内容啦!创作不易,如果你有任何问题,欢迎私信,感谢您的支持!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/709793.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue + leaflet实现图标指定方向随机旋转

效果 github地址 官方示例Demo 安装leaflet-rotatedmarker npm install leaflet-rotatedmarker -S引入leaflet.rotatedmarker import leaflet-rotatedmarker实现 this.laryerGroup this.$L.layerGroup() data.forEach(item > {this.layerGroup.addLayer(this.getMarke…

【tomcat知识点和部署】

文章目录 一、tomcat概述1.1 tomcat的介绍1.2 tomcat的特点 二、tomcat核心组件2.核心组件的介绍2.1 Web容器2.2 servlet容器2.3 JSP容器2.4 Tomcat核心组件的请求方式(交互方式)2.4.1 Web容器2.4.2 JSP容器2.4.3 serverlet容器2.5 Tomcat处理请求&#…

第六章 linux调试器——gdb的使用

第六章 linux调试器——gdb的使用 一、前提1、debug与release2、gdb的安装 二、常用调试指令1、开始调试2、代码显示3、断点设置4、代码执行5、信息监控6、退出调试 一、前提 1、debug与release 程序最终的发布方式分成两种,一种是debug模式,一种是rel…

华为OD机试真题 Python 实现【机器人活动区域】【2023Q1 200分】

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Python算法源码六、效果展示1、输入2、输出 一、题目描述 现有一个机器人,可放置于 M N的网格中任意位置,每个网格包含一个非负整数编号。当相邻网格的数字编号差值的绝对值小于等于 1 时&a…

redis-单节点安装

daemonize yes port 6379 bind 0.0.0.0 requirepass 123456 save 3600 1 300 100 60 10000dir /usr/local/redis dbfilename dump.rdb logfile redis.log pidfile redis.pid##save 3600 1 300 100 60 10000 ##3600秒(一小时),至少有一个值的话,会进行存盘 ##300秒(五分钟),至少…

探索性测试: 工具和方法的综合应用

1、前言 2、工具的使用 1、测试管理工具 2、缺陷跟踪工具 3、测试自动化工具 4、探索性测试工具 5、代码覆盖率工具 6、日志分析工具 7、网络抓包工具 8、数据库查询工具 9、并发和负载测试工具 10、安全测试工具 11、API测试工具 12、数据生成工具 13、异常处理和边界测试工具…

server2012远程桌面RDP120过期后修改

运行regedit 进入 HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Terminal Server \ RCM \ GracePeriod ,选中 GracePeriod 重启电脑Ok

572. 另一棵树的子树

另一棵树的子树 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right class Solution:def isSubtree(self, root: Optional[Tre…

ROS 编码器转Odom

双轮差速模型 移动距离 delta_dist (encoder_right encoder_left)/linesNum * circumference / 2; 旋转角度 Delta_th (float)(encoder_right - encoder_left) / wheel_track; 将移动距离转换到车体坐标系 delta_x cos(delta_th) * delta_dist; delta_y -sin(delta_th) * …

前端页面优化策略

目录 1 为什么要优化2 优化方案3 加载策略优化3.1 script执行时机3.2 预加载资源prefetch 和 preloaddns-prefetch 和 preconnect 4 骨架屏4 资源请求优化4.1 图片懒加载及异步解码方案 1 为什么要优化 从用户角度看,优化能够让页面加载得更快、对用户操作响应更及…

领域事件驱动DDD(一) 值对象以及实体

对领域事件驱动的一些知识的梳理(以下内容是从内到外进行梳理) 值对象:一个没有标识符的对象。 值对象通常不会被修改,而是通过创建新的值对象来表示不同的状态。 没有自己的生命周期,它们随着所属的实体或聚合根的…

自动化测试-Selenium

目录 什么是自动化测试 Selenium介绍 Selenium是什么 Selenium特点 Selenium工作原理 SeleniumJava环境搭建 1.下载chrome浏览器,查看版本号. 2.下载chrome浏览器驱动 3.配置环境变量 4.创建java项目,在pom文件中添加依赖 5. 验证环境是否搭建成功 Selenium常用API…

libevent实践08:实现定时器第二季

简介 获取libevent的版本号字符串 /**Get the Libevent version.Note that this will give you the version of the library that yourecurrently linked against, not the version of the headers that youvecompiled against.return a string containing the version numbe…

利用RabbitMQ实现消息投递削峰填谷

目录 异步和同步如何选择 异步线程 同步收发消息 一、导入依赖库 二、创建RabbitMQ配置类 三、创建消息任务类 异步和同步如何选择 依靠多线程,Java代码可以同步执行也可以异步执行 RabbitMQ提供了同步和异步两种收发消息模式 我们采用 Java异步线程 MQ同步…

MongoRepository

一、介绍 MongoRepository是一个接口,与HibernateRepository类似,通过继承MongoRepository接口,我们可以非常方便地实现对一个MongoDB集合中的文档数据进行增删改查,示例如下所示: import org.bson.types.ObjectId; import org.springframework.data.mongodb.repository…

[数据结构 -- 手撕排序第一篇] 插入排序

目录 1、常见的排序算法 2、插入排序的思路 2.1 基本思想 2.2 直接插入排序 2.2.1 单趟排序的思路 2.2.2 单趟排序代码实现 3、插入排序代码 4、插入排序打印测试 5、插入排序的时间复杂度 5.1 最坏情况 5.2 最好情况 6、直接插入排序的特性总结 1、常见的排序算法 2、插入排序…

SpringMVC (二) 第一个MVC程序

学习回顾:SpringMVC (一) 什么是SpringMVC Hello,SpringMVC 现在我们来看看如何快速使用SpringMVC编写我们的程序吧! 一、配置版 1、新建一个Moudle , springmvc-02-hello , 添加web的支持&…

Spring面试题--AOP

什么是AOP,你们项目中有没有使用到AOP? AOP称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect&a…

2024中山大学898水文地质与工程地质考研初试复习资料

C8260153[电子书]2024年中山大学898水文地质与工程地质考研精品资料 说明:本套资料由高分研究生潜心整理编写,高清电子书,考研推荐资料。 一、考研真题及重点名校真题 1.附赠重点名校真题 ①重点名校:水文地质学基础2010-2013…

魏副业而战:抖音图文带货玩法,月入5w+

我是魏哥,与其在家躺平,不如魏副业而战! 最近魏哥一直在研究短视频带货,看了很多案例,发现了一些NB的账号。 说真的,视频带货真的可以认真的研究研究,不管是做直播,还是发视频&…