【Spring 】执行流程解析:了解Bean的作用域及生命周期

 哈喽,哈喽,大家好~ 我是你们的老朋友:保护小周ღ  


今天给大家带来的是 Spring 项目的执行流程解析 Bean 对象的6 种作用域以及生命周期本文将为大家讲解,一起来看看叭~


本期收录于博主的专栏:JavaEE_保护小周ღ的博客-CSDN博客

适用于编程初学者,感兴趣的朋友们可以订阅,查看其它 “JavaEE基础知识”。

更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘


一、Spring 的执行流程 

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

 Spring 注解相关操作感兴趣得老铁可以阅读博主得另一篇博客:

【Spring】使用注解读取和存储Bean对象_保护小周ღ的博客-CSDN博客


二、Bean 的作用域

Spring 是一个包含众多工具方法的 IoC 容器,也可以认为 Spring 就是用来读取和存储 Bean 对象的,那么 Bean 对象就是Spring 中一个至关重要的角色。

2.1 通过案例来观察 Spring 中Bean 对象默认的作用域

设计一个公共的 Student 类的Bean对象,注册到 Spring 容器中,提供给  A用户 和 B用户使用,A用户不讲武德悄悄地修改 Student 类型Bean 对象的数据,B 用户在使用的 Bean 对象的时候发现数据已经被篡改了,相当的恼火~

Student 类如下:

@Data
public class Student {
    private int id; // 学号
    private String name; // 姓名
    private int age; // 年龄
    private String sex; // 性别
}

给大家介绍一个第三方的框架: lombok 

"Lombok"是一个在Java开发中非常常用的开源框架。它的目标是通过自动化生成Java代码的样板代码来简化开发过程,减少冗余代码,并提高代码的可读性。

Lombok提供了一系列的注解,例如@Data、@Getter、@Setter、@NoArgsConstructor等,通过在类上添加这些注解,可以自动生成对应的getter、setter、构造函数等方法。这样可以大大简化Java类的编写,提高开发效率

要使用Lombok,您需要在项目中添加Lombok的依赖,并在IDE中安装Lombok插件,以便在编译和运行时正确处理Lombok的注解。

 Lombox 依赖:

 <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
      <scope>provided</scope>
 </dependency>

博主使用 @Data 注解就来源于 lombox ,@Data包含了 @Setter 和 @Getter  注解,也就是自动给Student 类创建 set 和 get 方法。


公共的Bean 对象,注入到 Spring 中:

@Component
public class Users {
    //使用方法注解将 学生张三注入到 Spring 中
    @Bean
    public Student getStu() {
        Student stu = new Student();
        stu.setId(123456);
        stu.setName("张三");
        stu.setAge(18);
        stu.setSex("男");
        return stu;
    }
}

用户A 从Spring 中获取 stu Bean 对象,并进行修改:

@Controller
public class UserA {

    //从Spring 中获取Bean 对象
    @Resource //@Autowired
    private Student stu;

    public Student getStu() {
        System.out.println("用户A获取原Bean对象"+ '\n'+ stu.toString());

        //对原Bean 的数据进行修改
        stu.setName("李四");
        stu.setSex("女");
        return stu;
    }
}

用户B 从Spring 中获取 stu Bean 对象,进行使用(打印):

@Controller
public class UserB {
    //从Spring 中获取Bean 对象
    @Resource //@Autowired
    private Student stu;

    public Student getStu() {
        System.out.println("用户B获取被用户A修改过的 Bean :" + '\n' + stu.toString());
        return stu;
    }
}

启动类中获取用户A 和 用户B 对象,调用getStu() 方法,获取 stu Bean对象:

public class App {
    public static void main(String[] args) {
        //1. 获取Spring 上下文对象,里面管理着 bean 对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        //2. 获取指定的 Bean 对象
        UserA userA = context.getBean("userA", UserA.class);
        Student stuA = userA.getStu();
        System.out.println("用户A:" + stuA.toString());


        UserB userB = context.getBean("userB", UserB.class);
        Student stuB = userB.getStu();
        System.out.println("用户B:"+ stuB.toString());
    }
}


案例分析:

以上操作的的执行结果的原因 Bean 默认情况下是单例模式(singleton:一个类只有一个实例),也就是说用户 A 和 用户 B 操作的都是同一个Bean 对象,所以用户A 修改了唯一的 Bean , 用户B 获取到的 Bean 就是被修改后的了。

在Spring 中Bean 的作用域默认是singleton 单例模式~


2.2 Bean 对象的 6 种作用域

限定程序中变量的可用范围叫做作用域,Bean 对象的作用域指的是在 Spring 整个生命周期中的某种行为模式,例如:单例作用域(singleton)的意思就是在整个 Spring 中只有一份实例,且全局共享,当其他人修改了这个唯一的一份实例后,另一个人再获取到的实例,就是被修改后的值了。

Spring框架为Bean对象提供了多种作用域选项。以下是Spring框架中常见的6种Bean对象作用域:

  1. Singleton(单例):在整个应用程序中只存在一个Bean实例。每次请求都将返回相同的实例。获取Bean(通过applicationContext.getBean等方法获取),装配Bean(即通过@Autowired,@Resource)

  2. Prototype(原型):每次请求将创建一个新的Bean实例。每次请求都返回不同的实例。获取Bean(通过applicationContext.getBean等方法获取),装配Bean(即通过@Autowired,@Resource)

  3. Request(请求):在每次HTTP请求中,都会创建一个新的Bean实例。每个HTTP请求都返回不同的实例。

  4. Session(会话:在用户会话期间,都会创建一个新的Bean实例。对于同一用户的后续请求,将返回相同的实例。

  5. Global Session全局会话:在整个应用程序的全局会话期间,都会创建一个新的Bean实例。对于同一全局会话的后续请求,将返回相同的实例。

  6. Application应用程序:在整个Web应用程序的生命周期内,都会创建一个新的Bean实例。每个Web应用程序都返回相同的实例。

注意:作用域的使用取决于具体的应用场景和需求。Spring框架还支持自定义作用域,普通的Spring 项目只支持 singleton (单例),prototype (多例),剩下的4种状态是在 SpringMVC项目中可以设置。


2.3 给Bean 对象设置作用域

使用 @Scope 标签就可以用来声明 Bean 的作用域, 如以下代码所示:

@Component
public class Users {
    //声明为多例模式,每此请求都会实例一个新的Bean对象
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
    //使用方法注解将 学生张三注入到 Spring 中
    @Bean(name = "stu") //给 Bean 对象起一个名字
    public Student getStu() {
        Student stu = new Student();
        stu.setId(123456);
        stu.setName("张三");
        stu.setAge(18);
        stu.setSex("男");
        return stu;
    }
}

@Scope 标签既可以修饰方法也可以修饰类,此处是修饰方法,@Scope 有两种设置方式:

1. 直接设置值: @Scope("prototype")

英语好的朋友可以直接把单词记住,也是蛮直接方便的昂~

2.使用枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

此时我们给上述例子Student 类型的Bean 对象设置了多例模式,这个时候运行一下看看:


三、Bean 的生命周期

所谓 Bean(对象) 生命周期指的就是一个普通对象从创建到销毁的整个过程,我们把整个过程称之为对象的生命周期。Bean 对象也就是一个普通的实例对象。

Bean 对象的生命周期分为以下五个部分:

1. 实例化: Bean (为 Bean对象分配内存空间(堆区))

2. 设置属性:在实例化后,容器会将配置的属性值或引用注入到Bean对象中,可以通过构造函数、setter方法或字段注入的方式完成。

3. Bean 对象的初始化 :Bean对象的初始化流程通常包括以下几个步骤:

  • 加载Bean定义:首先,容器会读取配置文件或通过注解扫描等方式,获取Bean的定义信息,并将其存储在内存中。

  • 创建Bean实例:根据Bean的定义信息,容器会实例化Bean对象。这可以通过调用默认构造函数或使用工厂方法等方式来完成。

  • 注入依赖:一旦Bean实例创建完成,容器会检查Bean定义中所声明的依赖关系,并将相应的依赖注入到Bean实例中。依赖注入可以通过构造函数、setter方法或字段注入方式来实现。

  • 实现Aware接口:如果Bean实现了特定的Aware接口(如BeanNameAware、BeanFactoryAware等),容器会调用相应的回调方法,以便提供一些额外的关于容器的信息。

  • Bean初始化前的处理:在Bean实例初始化之前,容器会调用BeanPostProcessor接口的实现类的postProcessBeforeInitialization()方法,允许开发者在初始化之前进行一些自定义逻辑的处理。

  • 初始化Bean:实例化过程完成后,容器会根据Bean定义中的配置调用初始化方法。这可以是通过在Bean类中标注@PostConstruct注解或实现InitializingBean接口的afterPropertiesSet()方法来完成。

  • Bean初始化后的处理:在Bean实例初始化之后,容器会再次调用BeanPostProcessor接口的实现类的postProcessAfterInitialization()方法,允许开发者在初始化之后进行一些自定义逻辑的处理。

  • 完成Bean的初始化:至此,Bean的初始化流程完成,可以将其添加到容器中,供其他Bean进行依赖注入或其他操作使用。

需要注意的是,以上是一个典型的Bean对象初始化流程,实际应用中可能会有一些差异,例如,使用了代理、继承了父类等情况会导致初始化流程有所不同。同时,不同的容器实现也可能会有一些细微的差异。

4. 使用 Bean : Bean 对象,就是一个普通的实例化的对象,使用都是一样的,看咋类是咋设计的

5. 销毁 Bean :

销毁Bean对象可以通过以下几种方式实现:

  • 使用Destroy方法:可以在Bean类中实现DisposableBean接口,并重写其中的destroy()方法。在容器销毁Bean实例时,会自动调用该方法来销毁Bean对象。
public class MyBean implements DisposableBean {
    // ...
    
    @Override
    public void destroy() {
        // 销毁操作
        // ...
    }
}

  • 使用@PreDestroy注解:可以在Bean类的销毁方法上添加@PreDestroy注解,当容器销毁Bean实例时,会触发该注解标记的方法进行销毁操作。
public class MyBean {

    // ...
    
    @PreDestroy
    public void destroy() {
        // 销毁操作
        // ...
    }
}

  • 配置销毁方法:在配置文件(如XML配置文件)中,可以通过指定destroy-method属性来指定Bean销毁时调用的方法。该方法可以是Bean类中的任意公开方法。
<bean id="myBean" class="com.example.MyBean" destroy-method="destroy">
    <!-- ... -->
</bean>

需要注意的是,销毁Bean对象的时机由容器管理,通常发生在容器关闭时。如果是单例Bean,则在容器关闭或手动调用销毁方法时触发销毁操作。如果是原型或会话作用域(session scoped)的Bean,则需要手动销毁。


执行流程图 :


实例化和初始化的区别:

实例化和属性设置时 Java 级别的系统 “事件”,操作过程不可以人为干预,而初始化是给开发者提供的,可以在实例化之后,类加载完成之前进行自定义 “事件” 处理。

总的来说,实例化是创建Bean实例的过程,而初始化是对已创建的Bean对象进行属性赋值和回调方法调用的过程。实例化是创建Bean对象的基础步骤,而初始化则是在实例创建完成后对Bean对象进行配置和准备的重要步骤。


举个例子形象的描述Bean 对象的生命周期:买房子

1. 实例化:在某市盖了一套毛坯房(从无到有,将字节码转换为内存中的对象,只是分配了内存)

2. 设置属性:(容器会将配置的属性值或引用注入到Bean对象中)。购买装修材料,引入外部资源。

3. 初始化:给房子装修~

  • 各种通知:联系各种装修师傅,水工,电工,瓦工……
  • 初始化的前置工作:装修师傅现场考察毛坯房的环境,制定装修方案。
  • 进行初始化工作:(@PostConstruct 初始化、init-method 初始化),装修师傅进行装修,其中有装修技术好的,有装修技术差的。
  • 初始化的后置工作: 装修完毕之后对房子进行清理。

4. 使用 Bean 对象: 拎包入住~

5. 销毁 Bean 对象: 拆,或者卖掉这套房子~

一定是先设置属性,再进行初始化操作。


好了,到这里,【Spring 】执行流程解析:了解Bean的作用域及生命周期 博主已经分享完了,希望对大家有所帮助,如有不妥之处欢迎批评指正。 

下期预告:【SpringBoot】框架~

感谢每一位观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* 

遇见你,所有的星星都落在我的头上……

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据库应用:MySQL高级语句(一)

目录 一、理论 1.常用查询 2.函数 3.进阶查询 二、实验 1.普通查询 2.函数 3.进阶查询 三、问题 1.MySQL || 运算符不生效 四、总结 一、理论 1.常用查询 常用查询包括&#xff1a;增、删、改、查&#xff1b; 对 MySQL 数据库的查询&#xff0c;除了基本的查询外…

网络安全能力成熟度模型介绍

一、概述 经过多年网络安全工作&#xff0c;一直缺乏网络安全的整体视角&#xff0c;网络安全的全貌到底是什么&#xff0c;一直挺迷惑的。目前网络安全的分类和厂家非常多&#xff0c;而且每年还会冒出来不少新的产品。但这些产品感觉还是像盲人摸象&#xff0c;只看到网络安…

09_SPI-Flash 页写实验

09_SPI-Flash 页写实验 1. 实验目标2. 操作时序3. 模块框图3.1 顶层模块3.2 页写模块 4. 波形图5. RTL5.1 flash_pp_ctrl5.2 spi_flash_pp 6. Testbench6.1 tb_flash_pp_ctrl6.2 tb_spi_flash_pp 1. 实验目标 使用页写指令&#xff0c;向 Flash 中写入 N 字节数据&#xff0c;…

Linux查看某进程所部署的目录路径

1.首先查看系统中正在跑的进程都有什么 ps -ef 2.然后通过抓取你要看的进程名&#xff0c;比如哪些服务 ps -ef | grep xxxxx(服务名) Linux在启动一个进程时&#xff0c;系统会在 /proc 下创建一个以PID命名的文件夹&#xff1b; 在该文件夹下会有我们的进程的信息&#…

高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测教程

详情点击链接&#xff1a;高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测 第一&#xff1a;预测平台及安装 一、高精度气象预测基础 综合气象观测数值模拟模式&#xff1b; 全球预测模式、中尺度数值模式&#xff1b; 二、自动化预测平台 Linux系统 Crontab…

redis 相关

redis相关面试题 redis支持哪几种数据形式&#xff1f; String,hash,set,zset,list redis主要消费什么物理资源&#xff1f; 内存&#xff0c;key-value的形式&#xff0c; redis 具有快速和数据持久化的特征&#xff0c;如果不将数据放在内存中&#xff0c;磁盘 I/O 速度为严…

PWM呼吸灯+流水灯设计

完成任务&#xff1a; 在流水灯基础上加入pwm呼吸灯设计&#xff0c;关于pwm呼吸灯设计可以看博主上一篇博客PWM呼吸灯设计 &#xff0c;开发板上灯每两秒进行一次切换&#xff0c;每一个的亮灭间隔为一秒。 代码参考&#xff1a; module pwm_led_change(input wire …

element-ui select数据回显显示数字的问题 el-select校验失效出现阿拉伯数字问题

初始化参数 return {fields: [{"title":"景区","id":0},{"title":"酒店","id":1}],evaluates: [{"title":"好评","id":0},{"title":"中评","id":1…

Spring Data JPA使用规则和审计的学习

一、引入依赖 完整的pom文件如下所示: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

css3的新特性

动画效果 过渡 transition 鼠标放上去瞬间变大 过渡是变大的过程慢慢变化 第一个参数&#xff1a;对哪些值进行过渡。all为hover中所有&#xff0c;也可以指定属性 第二个参数&#xff1a;让动画过渡多长时间。要添加单位&#xff08;s秒&#xff09; 第三个参数&#xff1…

Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么

目录 Chat GPT是什么 初学者怎么使用Chat GPT 使用Chat GPT需要注意什么 一些简单的prompt示例 Chat GPT是什么 Chat GPT是由OpenAI开发的一种大型语言模型&#xff0c;它基于GPT&#xff08;Generative Pre-trained Transformer&#xff09;架构。GPT是一种基于深度学习的…

微信小程序音频播放失败:TypeError: Cannot read property ‘duration‘ of undefined

报错截图 最下面这个this.setData()报错可不用理会&#xff0c;是this取值的问题 解决 需要播放和暂停功能时&#xff0c;需要把audio以及他的src放在Page外面。不能缺少 audioCtx.onPlay() 和 audioCtx.onError()两个方法&#xff0c;且需要放在play()方法之前如果在wx.crea…

ChatGPT助力DevOps的优势与局限

一、前言 DevOps 是一种方法论&#xff0c;旨在提高软件开发和 IT 运营团队的协作和效率。DevOps 涉及各种任务和流程的自动化&#xff0c;例如规划、编码、测试、部署、监控和故障排除。然而&#xff0c;其中一些任务和流程仍然有大量任务需要人工手动处理&#xff0c;而这会…

关于WIN10创建系统映像时D盘为系统盘的解决方案

文章目录 问题&#xff1a;使用WIN10自带备份工具时&#xff0c;创建系统映像时&#xff0c;D盘被识别为系统盘的解决方案。方法一&#xff08;传统方法&#xff0c;删盘符&#xff09;方法二&#xff08;对症下药&#xff0c;找原因&#xff09;第一个选项是暂时将服务的Image…

广西学子复读15年,不服从分配。网友:完全是浪费时间

广西学子复读15年&#xff0c;不服从分配。网友&#xff1a;完全是浪费时间 唐尚珺的复读行为引起了网友们的不同解读。有人认为他是一个执念深重的人&#xff0c;目标是考上清华北大&#xff0c;但这个说法是否真实&#xff0c;我们无法确定。无论如何&#xff0c;我们必须认识…

DBeaver连接华为高斯数据库 DBeaver连接Gaussdb数据库 DBeaver connect Gaussdb

DBeaver连接华为高斯数据库 DBeaver连接Gaussdb数据库 DBeaver connect Gaussdb 一、概述 华为GaussDB出来已经有一段时间&#xff0c;最近工作中刚到Gauss数据库。作为coder&#xff0c;那么如何通过可视化工具来操作Gauss呢&#xff1f; 本文将记录使用免费、开源的DBeaver来…

ARM 架构是什么?

ARM&#xff08;Advanced RISC Machines&#xff09;架构是一种处理器架构&#xff0c;它是一种精简指令集计算机&#xff08;RISC&#xff09;架构。ARM架构最初由ARM Holdings&#xff08;现在是SoftBank Group的子公司&#xff09;开发&#xff0c;并在1980年代末和1990年代…

MySQL 第七天作业 nosql作业

作业一&#xff1a;string list hash结构中&#xff0c;每个至少完成5个命令&#xff0c;包含插入 修改 删除 查询&#xff0c;list 和hash还需要增加遍历的操作命令 1、 string类型数据的命令操作&#xff1a; &#xff08;1&#xff09; 设置键值&#xff1a; set key1 re…

存储服务的演化与MySQL分库分表

文章目录 一、存储服务的演化1.单体结构2.单表单库的数据量膨胀 -> 分库分表3.单个MySQL的读写压力过大 -> MySQL索引优化4.进一步缓解MySQL读写压力 -> 读写分离5.冷热数据分离 -> 使用Redis缓存 二、MySQL分库分表1.策略2.需要注意的问题 一、存储服务的演化 1.…

基于单片机汽车防盗报警的设计与实现

功能介绍 以STM32单片机作为主控系统&#xff1b;LCD1602液晶显示当前温度信息和参数等功能&#xff1b;3个LED指示灯表示&#xff1a;震动指示灯、人体感应指示灯、防盗模式开启指示灯&#xff1b;按键用来开启防盗模式&#xff0c;设置温度上下限&#xff1b;开启防盗后检测到…