Spring Bean的作用域和生命周期

news2024/11/24 0:29:06

文章目录

  • 1. Bean的作用域
  • 2. Spring的生命周期
  • 3. Bean的生命周期
  • 4. 相关注解总结

1. Bean的作用域

Bean 的作用域指的是 Bean 在 Spring 容器中的行为(Bean 实例创建及生命周期),它的行为是由 Spring 来管理的,可以根据具体情况选择不同的作用域来达到性能优化、资源利用最大化和可维护性等目的。

Bean 作用域(Scope)类型主要有如下几种:

其中前两种是 Spring 核心作用域,而后 4 种是 Spring MVC 中的作⽤域;

  1. singleton:单例模式(默认的作用域),Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个 Bean 引用它,始终指向同一对象,通常无状态的 Bean 使用该模式(无状态表示Bean对象的属性不需要更新),这也是 Spring 出于性能方面的考虑。
  2. prototype:原型模式(多例作用域),每次从 Spring 容器中获取 prototype 模式的 Bean 时,容器都将创建一个新的 Bean 实例,每个Bean实例都有自己的属性和状态,而 singleton 全局只有一个对象,通常有状态的 Bean 使用该作用域,即Bean的属性可能会更新。
  3. request:请求模式,在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例,在这次的请求和响应中共享这个 Bean,但在不同的请求中会创建新的实例,也就是说每次 HTTP 请求,使用的是不同的Bean, 类似于 prototype,在 Spring MVC 中使用,即使用需要在 WebApplicationContext 环境下。
  4. session:会话模式,在同一个 HTTP Session 中,共享使用的是一个 Bean 实例,例如记录用户的登录信息,在 Spring MVC 中使用。
  5. application:全局模式,表示整个 Web 应用的 http servlet context 共享同一个 Bean,主要记录的是的 Web 应用的上下文信息,例如记录一个应用的共享信息,在 Spring MVC 中使用。
  6. websocket:网络长连接,只适用于 Spring WebSocket 项目,在一个 HTTP WebSocket 的生命周期中(一次长连接),共享一个 Bean 实例;WebSocket 的每次会话中,保存了一个 Map 结构的头信息,用来保存客户端消息头,第一次初始化后,直到一次长连接结束都是用一个 Bean。

这里就简单用singletonprototype这两种可以在 Spring 核心代码中使用的模式来演示区别一下。

package com.tr.demo.model;

public class User {
    private int id;
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

一般有两种方式设置 Spring Bean 作用域:

  1. 使用xml配置的方式,我们将bean标签当中的scope属性设置为singleton就为单例,设置为prototype就为多例模式。img
  2. 二是直接通过@Scope注解,不设置参数或设置参数为singleton就为单例,设置为prototype就为多例模式。img
    我们还可在 Scope 注解中可以传入另一种参数形式,和上面直接拼写出来效果一样。
    img
    这种方式是 ConfigurableBeanFactory 类中为我们提供了静态属性,相较于自己拼写不容易出错。img

我们来看一下 singleton 和 prototype 两种模式下获取的 Bean 有什么不同,我们这里演示在这两种不同的模式下将 User 对象放到 Spring 容器中,从容器中先后两次取出 User,看这两次取出的 Bean 是否相同。

public static void main(String[] args) {
    ApplicationContext context =
            new ClassPathXmlApplicationContext("spring-config.xml");

    User user1 = context.getBean("user", User.class);
    User user2 = context.getBean("user",User.class);
    System.out.println(user1 == user2);
}

singleton 模式下的结果:

可以看到,此时 User 类在 Ioc 容器中只创建了一个实例,而通过 applicationContext.getBean() 方法多次获取到的 Bean,都是同一个对象实例,相当于是一个浅拷贝。

img
prototype 模式下的结果:

这里之所以这里打印出来的 Bean 是 2 个而不是 3 个,是因为prototype模式下在我们创建容器时并不会进行 Bean 的实例化,它在我们获取 Bean 的时候才会去创建 1 个实例,而且每次获取 Bean 时都会创建新的实例,它们彼此之间都是不同的实例,相当于是一个深拷贝。

img

2. Spring的生命周期

Spring 的生命周期大致走的的是如下流程

  1. 首先启动容器,加载配置文件(类加载路径下的 spring-config.xml 文件)。
    img
  2. 根据配置文件完成 Bean 的实例化(分配内存空间)和初始化(初始化空间),包括扫描配置文件下带有五大类或者方法注解的类和 bean 标签中要注册的对象,配置文件中的 Bean 是按顺序实例化和初始化的。
    img
  3. 将 Bean 注册到 Spring 容器中
  4. 装配 Bean 的属性,如果 Bean 对象需要其他的 Bean 作为属性,可以使用注解的方式注入(@Autowired、Resource)
    img

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

3. Bean的生命周期

Bean 的生命周期,就是 Bean 对象从诞生到销毁的整个过程,Bean 的生命周期大致有 5 个阶段:

①Bean 的实例化(分配内存空间)。

②设置 Bean 属性(进行依赖注入,将依赖的 Bean 辅助到当前类的属性上)。

③Bean 的初始化阶段:

  • 执行各种通知,底层实现了 Aware 接口,执行其中的方法,如:BeanNameAware、BeanFactoryAware、ApplicationContextAware 的接口方法;
  • 执行初始化的前置方法,即执行 BeanPostProcessor 方法(before);
  • 执行初始化方法 ,依赖注⼊操作之后被执⾏(两种重写方式:xml方式,注解方式@PostConstruct);
  • 执⾏⾃⼰指定的 init-method ⽅法(如果有指定的话);
  • 执行 BeanPostProcessor 初始化后置方法(after)。

④使用 Bean。

⑤销毁 Bean,执行 销毁容器的各种⽅法,如 @PreDestroy、DisposableBean 接⼝⽅法、destroy-method。

要注意设置属性必须在初始化之前,因为有可能在初始化的时候使用Bean。

上述流程可以以⽣活中的场景来理解它,⽐如我们现在需要买⼀栋房⼦,那么我们的流程是这样的:

  1. 先买房(毛坯房),对应 Bean 的实例化;
  2. 装修,对应给 Bean 设置属性;
  3. 买家电,如洗⾐机、冰箱、电视、空调等,对应 Bean 的各种初始化
  4. ⼊住,对应使⽤ Bean;
  5. 卖房,对应 Bean 的销毁。

执行流程如下图所示:

img

还需要注意区分一下实例化和初始化,实例化和属性设置是 Java 级别的系统“事件”,其操作过程不可⼈⼯⼲预和修改;⽽初始化是给开发者 提供的,可以在实例化之后,类加载完成之前进⾏⾃定义“事件”处理。
下面就简单的写几个周期方法来演示一下这个过程,在类中添加两个方法,一个是init方法表示初始化,另外一个是destroy方法,表示Bean销毁前执行的事情,使用@PostConstruct注解或者xmlbean标签中的init-method属性表示在构造后执行,@PreDestroy注解或者xmlbean标签中的destroy-method表示在 Bean 销毁前做的事情。

import com.tr.demo.model.User;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class BeanLifeComponent implements BeanNameAware {
    @Autowired
    private User user;

    @Override
    public void setBeanName(String s) {
        System.out.println("执行了 BeanNameAware 通知 -> " + s);
    }

    @PostConstruct
    public void doPostConstruct() {
        System.out.println("执行了 @PostConstruct (注解式初始化)");
        System.out.println(user.toString());
    }

    public void myInit(){
        System.out.println("执行了 myinit (xml 式初始化)");
    }

    @PreDestroy
    public void doPreDestroy(){
        System.out.println("执行了 @PreDestroy (销毁 Bean 前执行)");
    }

    public void myDestroy() {
        System.out.println("执行了 myDestroy (销毁 Bean 前执行)");
    }

    public void sayHi(){
        System.out.println("使用 Bean");
    }
}

Spring 配置文件,将 Bean 手动存储在 Spring 容器中,要注意init-methoddestroy-method这两个属性的值要和上面实现的方法名对应。

<bean id="mybean" class="BeanLifeComponent"
      init-method="myInit" destroy-method="myDestroy">
</bean>

测试代码:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifeTest {
    public static void main(String[] args) {
        // 父类 ApplicationContext 中没有 close, destroy 系列方法
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanLifeComponent component =
                context.getBean("mybean",BeanLifeComponent.class);
        component.sayHi();
        // 关闭容器
        context.close();
    }
}

运行结果:

img如果代码中飘红说 @PostConstruct 和 @PreDestroy 注解如果找不到,需要导入下面的jar包。

<dependency>  
<groupId>javax.annotation</groupId>  
<artifactId>javax.annotation-api</artifactId>  
<version>1.3.2</version></dependency>

找不到的原因是,从 JDK9 以后 jdk 中的 javax.annotation 包被移除了,这两个注解刚好就在这个包中。

4. 相关注解总结

@Scope

名称@Scope
类型类注解
位置类定义上方
作用设置该类创建对象的作用范围 可用于设置创建出的bean是否为单例对象
属性value(默认):定义bean作用范围, 默认值singleton(单例),可选值prototype(非单例)

@PostConstruct

名称@PostConstruct
类型方法注解
位置方法上
作用设置该方法为初始化方法
属性

@PreDestroy

名称@PreDestroy
类型方法注解
位置方法上
作用设置该方法为销毁方法
属性

注解功能与 XML 实现对应关系:

img

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

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

相关文章

urllib爬虫模块

urllib爬取数据 import urllib.request as request# 定义url url "https://www.baidu.com" #模拟浏览器发起请求获取响应对象 response request.urlopen(url)""" read方法返回的是字节形式的二进制数据 二进制--》字符串 解码 decode( 编码的格式…

基于粒子群改进深度信念网络的回归分析,基于PSO-DBN的回归分析

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) 粒子群算法的原理 DBN的粒子群改进深度信念网络的回归分析 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算…

猿辅导《暑假一本通》:28天科学规划,帮助孩子保持学习状态

一直以来&#xff0c;有效利用寒、暑假期查漏补缺、解决偏科问题、初步养成好的自主学习习惯等是很多家长对学生的期望。但当前市面上教辅品类繁多&#xff0c;内容质量却参差不齐。据北京开卷统计数据显示&#xff0c;2022年前三季度零售市场上的教辅图书超过8000种&#xff0…

[NDK]从Opengles到Vulkan-基础篇(9)-视口相关

关于绘制调用的流程 我们可以看到整个流程步骤 1 光栅化2 裁剪测试3 多重采样4 深度测试5 模板测试6 混合7 抖动8 输出帧数据 这一节会涉及到裁剪测试 ##关于视口 我们需要先了解以下四个概念 1.屏幕:即计算机的整个屏幕大小。 2.窗口:即屏幕中的某一个窗口,可放大缩小和移…

通讯商二要素Api接口验证真伪

随着互联网的普及和各种社交平台、电商平台、金融平台的发展&#xff0c;许多业务都需要用户进行实名认证&#xff0c;这也就涉及到了手机号码和姓名的验证问题。为了解决这个问题&#xff0c;现在有很多运营商提供的二要素API接口能够进行手机号码和姓名的验证&#xff0c;本文…

使用Pandas进行数据清理的入门示例

数据清理是数据分析过程中的关键步骤&#xff0c;它涉及识别缺失值、重复行、异常值和不正确的数据类型。获得干净可靠的数据对于准确的分析和建模非常重要。 本文将介绍以下6个经常使用的数据清理操作&#xff1a; 检查缺失值、检查重复行、处理离群值、检查所有列的数据类型…

Qt打包程序 windeployqt

Qt Creator运行直接生成的可执行性程序不能直接使用&#xff0c;原因是缺少依赖库。直接运行会报错&#xff1a; 为可执行文件添加图标 为可执行文件添加 icon 图标的方法很简单&#xff0c;将事先准备好的 icon 图标拷贝到程序对应的文件夹中&#xff0c;然后在 pro 工程文…

Java课题笔记~ JSTL

使用EL表达式已经实现了页面输出显示的优化&#xff0c;为什么还需要使用JSTL呢&#xff1f; 这是因为使用EL表达式无法实现逻辑处理&#xff0c;如循环、条件判断等&#xff0c;因此还需要与Java代码混合使用&#xff0c;而JSTL则可以实现逻辑控制&#xff0c;从而进一步优化…

中小企业选择Zoho CRM的五大优点

一款适用于中小企业的CRM客户关系管理软件&#xff0c;它可以帮助企业提高销售效率&#xff0c;改善营销效果&#xff0c;优化业务流程&#xff0c;实现业绩增长。下面说说&#xff0c;中小企业为什么要选择Zoho CRM&#xff1f; 1、多种版本定价 CRM需要提供了多种定价方案&…

三相电机的烧毁原因以及如何保护

三相电动机&#xff0c;具有一定的过载能力&#xff0c;短时间过载对电动机的影响不大&#xff0c;但是&#xff0c;电动机的电流长时间超过额定电流&#xff0c;就会使电动机严重发热而损坏&#xff0c;如果电动机定子绕组内部发生短路&#xff0c;也会使绕组电流增加而烧毁电…

07 - 深入浅出HashMap的设计与优化

在上一讲中提到过 Collection 接口&#xff0c;那么在 Java 容器类中&#xff0c;除了这个接口之外&#xff0c;还定义了一个很重要的 Map 接口&#xff0c;主要用来存储键值对数据。 HashMap 作为我们日常使用最频繁的容器之一&#xff0c;相信你一定不陌生了。今天我们就从 …

Java SpringBoot Vue智能停车系统

基础环境 JDK1.8、Maven、Mysql、IntelliJ IDEA 内置功能 系统管理&#xff1a;角色管理、接口管理、系统菜单、全局配置 账号管理&#xff1a;用户管理、合作单位 系统监控&#xff1a;监控大屏、日志监控 财务管理&#xff1a;订单列表 停车记录&#xff1a;停车记录 车辆管…

再不学就晚了!学习嵌入式的五个好处

学习嵌入式技术带来的好处不仅限于提高就业竞争力&#xff0c;还能为你提供其他各种各样的潜在优势。种一棵树最好的时间是十年前&#xff0c;其次就是现在&#xff0c;是时候立刻开始学习嵌入式技术了&#xff01; 1. 多样的就业机会 嵌入式技术已经广泛应用于各行各业&#x…

基于STM32CUBEMX驱动TMOS模块STHS34PF80(4)----中断获取信号

基于STM32CUBEMX驱动TMOS模块STHS34PF80----4.中断获取信号 概述样品申请视频教程参考Demo参考程序中断中断生成设置中断开启存在检测中断输出配置中断管脚主程序测试结果 概述 HS34PF80的数据准备信号提供了一种机制&#xff0c;允许设备在新的测量数据可读取时通知系统&…

86. 分隔链表

86. 分隔链表 题目-中等难度示例1. 新建两链表&#xff0c;根据x值分类存放&#xff0c;最后合并 题目-中等难度 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保…

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!

Spring源码 参考资料 https://www.bilibili.com/video/BV1Tz4y1a7FM https://www.bilibili.com/video/BV1iz4y1b75q bean的生命周期 bean–>推断构造方法&#xff08;默认是无参构造&#xff0c;或指定的构造方法&#xff09;–>实例化成普通对象&#xff08;相当于ne…

【Vue3】Vue3 UI 框架 | Element Plus —— 创建并优化表单

安装 # NPM $ npm install element-plus --save // 或者&#xff08;下载慢切换国内镜像&#xff09; $ npm install element-plus -S// 可以选择性安装 less npm install less less-loader -D // 可以选择性配置 自动联想src目录Element Plus 的引入和注入 main.ts import…

S7-200 Smart 的多种端口及通讯方式

每个S7-200 SMART CPU都提供一个以太网端口和一个RS485端口(端口0)&#xff0c;标准型CPU额外支持SB CM01信号板(端口1)&#xff0c;信号板可通过STEP 7-Micro/WIN SMART软件组态为RS232通信端口或RS485通信端口。 CPU 通信端口引脚分配 1.S7-200 SMART CPU 集成的 RS485 通信…

数据结构入门 — 时间复杂度、空间复杂度

前言 数据结构_空间复杂度_时间复杂度讲解_常见复杂度对比 本文介绍数据结构中的时间复杂度和空间复杂度 ***文章末尾&#xff0c;博主进行了概要总结&#xff0c;可以直接看总结部分*** 博主博客链接&#xff1a;https://blog.csdn.net/m0_74014525 点点关注&#xff0c;后期…

防静电实时监控系统具有哪些功能

防静电实时监控系统是一种用于监测、检测和控制静电产生和积累的系统。它通过使用各种传感器和仪器&#xff0c;实时监测环境中的静电情况&#xff0c;并及时采取措施来防止静电危害和事故的发生。 防静电实时监控系统通常具有以下功能&#xff1a; 1. 传感器监测&#xff1a;…