【JavaEE】深入了解Spring中Bean的可见范围(作用域)以及前世今生(生命周期)

news2024/9/21 5:50:17

【JavaEE】Spring的开发要点总结(4)

在这里插入图片描述

文章目录

  • 【JavaEE】Spring的开发要点总结(4)
    • 1. Bean的作用域
      • 1.1 一个例子感受作用域的存在
      • 1.2 通过例子说明作用域的定义
      • 1.3 六种不同的作用域
        • 1.3.1 singleton单例模式(默认作用域)
        • 1.3.2 prototype原型模式
        • 1.3.3 request请求作用域
        • 1.3.4 session会话作用域
        • 1.3.5 application全局/应用作用域
        • 1.3.6 "websocket" HTTP WebSocket作用域
      • 1.4 设置Bean的作用域
    • 2. Bean的生命周期
      • 2.1 Spring的执行流程
      • 2.2 Spring 的生命周期
      • 2.3 Bean的生命周期
        • 2.3.1 Bean初始化
        • 2.3.2 Bean生命周期代码演示
        • 2.3.3 为什么属性设置比Bean初始化早

【JavaEE】Spring的开发要点总结(4)

在学习Spring中,Bean是最核心的操作资源

  • 使用学习Bean对象是一个重点,我们已经知道如何存储它,获取它,现在我们要知道:
  1. 它的作用域,我们才可以知道怎么使用,才能得心应手,符合预期~
  2. 它的生命周期,我们才能更加清楚的了解它的“生与死”,即程序执行的过程~

1. Bean的作用域

在学习C语言或者JavaSE的时候,熟悉一个变量的作用域非常重要,否则会出现很多错误,并且违背一些设计上的初心~

  • C语言
    • 全局变量,整个源文件可以访问,代码从上到下执行,局部优先,隔着源文件需要extern…
    • 局部变量,在代码块中生效,在方法中生效,代码从上到下执行
    • 静态变量,局部变量的作用域,全局变量的生命周期~
  • Java
    • 修饰访问限定符
    • 局部变量…
    • 成员变量,静态成员变量…

知己知彼,才能百战百胜~

1.1 一个例子感受作用域的存在

之前的代码,我们只是一个简单的读操作,没有涉及其他,所以作用域感受不明显,接下来一个例子说明一下~

背景故事:

一个公司开发了一个外卖平台,这个公司打算将这个平台卖给别的公司,赚收成和维护费,但是每个公司都有特定的要求,而员工三人(小马、大马、老马),负责这个项目,小马负责公司原本的代码,大马负责A公司的外卖平台的代码,老马则负责B公司。

大马和老马的工作就是,对一些功能进行删减,添加个别的功能~

三人各自完成各自的业务~

所以就会如下的项目结构(实际情况要比这复杂很多,这个例子只是为了演示罢了):

在这里插入图片描述

  • 小马代表UserController
  • 大马代表UserController1
  • 老马代表UserController2

这个Users类,就是一些原始的User的诞生和定义的地方~

  • 这个类是一个公共类
    • 这不代表这个里面诞生的对象就是公共的,而是存储Bean对象的手段是公共的

在这里插入图片描述

那么可能就会有以下场景:

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


再每次设置后都打印一次:

System.out.println(user2);

他们原本的意思就是,他们从spring中获取一个Bean对象(用户),设置对应的属性,为自己所用~

现在我们来测试一下:

@Component
public class Test {

    @Autowired
    private UserController userController;
    @Autowired
    private UserController1 userController1;
    @Autowired
    private UserController2 userController2;

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        Test test = context.getBean("test", Test.class);
        test.userController.doMethod();
        test.userController1.doMethod();
        test.userController2.doMethod();
    }
}

在这里插入图片描述

从结果可以看出,下一次的更新,是在前一次更新的基础上进行的!

  • 而小马大马老马三个人的操作都没有问题,他们都不知道对方进行修改了 ~

所以可以说明,他们用的Bean,是同一个!就像C语言全局变量那样~

这就是作用域中的一种:单例Bean对象

  • 这里的单例跟我们之前的单例不一样,之前的单例是那个类的实例只有一个
  • 而这里的单例是,这个Bean对象的实例只有一个
    • 也就是说这个类型的Bean对象,名字为这个名字的Bean对象,有且只有一个~

改变Bean对象的作用域也很简单,只需要一个注解@Scope(意思就是作用域)~

在这里插入图片描述

默认情况下就是:singleton

在这里插入图片描述

在这里插入图片描述

我们如果要让小马大马老马获得的Bean对象都不一样,可以设置为:

prototype(原型/多例)

  • 原型 => 每次获取该 Bean对象,都是重新获取初始的那一个
  • 多例 => 这个类型这个名字的 Bean对象,有多个存在!

在这里插入图片描述

在这里插入图片描述

  • 从结果可以看出,作用域的改变!

1.2 通过例子说明作用域的定义

Bean的作用域指的就是Bean对象在Spring整个框架中的某种行为模式:

  1. 比如singleton,单例模式,就表示这个Bean对象在整个Spring容器中只有一份,它是全局共享的,那么当其他人修改这个值之后,另一个人读取到的就是修改后的值
  2. 再比如prototype,原型模式,就表示这个Bean对象在整个Spring中可以存在多份,并且每次DI的时候,都是崭新的一个Bean对象,不同人获得的Bean是不一样的
    • 所以prototype模式下的Bean对象的作用域就是:需要注入这个Bean的那个类的一个实例内部
    • 类比两个不同的方法中定义的同一类型同一名字的变量~

1.3 六种不同的作用域

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

Spring普通项目( Spring Core)其实就前面两种:singleton 和 prototype

后四种值则是在 Spring MVC 项目中的值

1.3.1 singleton单例模式(默认作用域)

单例模式的效率比较高(性能好)

  • 只有第一次去加载它

经典的面试题:单例模式的Bean是线程安全的吗?

不是线程安全的~

  • 所有人共同操作的变量,一定不是线程安全的

解决方案:使用ThreadLocal(本地线程变量)

  • 这是解决线程安全的其中一种方式!
    在这里插入图片描述

文章推荐:ThreadLocal不好用?那是你没用对!| Java Debug 笔记 - 掘金 (juejin.cn)

ThreadLocal的基础方法:

  1. set方法
  2. get方法
  3. remove方法

可能存太多没有remove,内存溢出的问题也会出现,感兴趣的可以去了解一下

相比于使用锁来解决线程安全问题

  • 使用ThreadLocal可能会导致结果与锁不一致的情况
  • 特别是在多个线程之间存在依赖关系的情况下。
    • 因为每个线程都有自己的数据副本,如果线程之间需要共享数据并进行协作,那么就需要额外的协调机制来保证数据的一致性。
    • 否则,可能会出现一个线程修改了数据,但其他线程并不知道的情况,导致结果不一致。

所以在使用ThreadLocal解决线程安全问题时,**需要根据具体的业务场景来评估是否适合使用ThreadLocal,**并确保线程之间的数据协作和一致性。

对于一些依赖全局状态的场景,使用锁可能更适合。

1.3.2 prototype原型模式

每次获取(DI)的都是一个原型的对象:

在这里插入图片描述

1.3.3 request请求作用域

顾名思义,在每一次HTTP请求的时候,创建一次原型,与prototype类似

在一次HTTP请求和响应中,共享Bean

注意:限定在Spring MVC中使用

因为Spring Core项目不支持HTTP

Spring MVC项目也叫作 Spring Web项目,支持HTTP

1.3.4 session会话作用域

顾名思义,一个HTTP Session中,共享Bean

  • 例如记录一个用户的登录信息,同一个session,每次获取Bean的时候不要原型

注意:限定在Spring MVC中使用

后面四种可能会比较难理解,这是因为我们还没有接触Spring MVC,所以不太了解具体用法!

  • 之后的实践肯定会对这些知识更加清晰!

1.3.5 application全局/应用作用域

在一个http servlet Context中,共享Bean

即一个Context容器,共享Bean

  • web应用的上下文信息,例如记录一个应用的共享信息

注意:限定在Spring MVC中使用

对于普通的Spring项目是不能用这个值的

但是对于singleton单例模式,Bean的作用域不超过一个ApplicationContext对象(一个context是一个容器,不同context进行各自的注入…):

在这里插入图片描述

singleton和application有什么区别呢?

  1. 前者是Spring Core的全局作用域,作用于IoC容器
  2. 后者是Spring MVC(Spring Web)的全局作用域,作用于Servlet容器

了解即可

1.3.6 “websocket” HTTP WebSocket作用域

在一个HTTP WebSocket的生命周期中,共享Bean

就是一个特殊项目里使用的特殊值罢了

注意:限定在Spring WebSocket中使用

WebSocket的每次会话中,保存了一个Map结构的头信息,将用来包裹客户端消息头。第一次初始化后,直到WebSocket结束都是同一个Bean。

如果对WebSocket项目感兴趣的同学可以去学习,如果不感兴趣,了解一下也可以

1.4 设置Bean的作用域

  1. 直接设置
    • @scope(“prototype”)
  2. 利用全局变量
    • 不用记忆单词,借助题词
      在这里插入图片描述

效果一致~

对于 & :了解即可!

在这里插入图片描述

2. Bean的生命周期

2.1 Spring的执行流程

笼统的流程:

  • 回答问题的时候,不用讲太细致~
  1. 启动容器

在这里插入图片描述

  1. 加载配置文件(根据参数)
    在这里插入图片描述

  2. 完成Bean的实例化(根据提供的扫描路径,找五大类注解)

    • 这样Bean对象就成型了,但是是游离在内存中
      在这里插入图片描述
  3. 注册Bean对象到容器中

在这里插入图片描述

  1. 装配Bean的属性(DI)
    在这里插入图片描述
    6.……

2.2 Spring 的生命周期

跟流程基本一致(粗糙的了解):

  1. 启动容器
  2. 读取配置进行Bean实例化
  3. 将Bean加入到容器中
  4. 装配Bean属性(给当前类的属性进行赋值,DI)
  5. 运行业务代码
  6. 销毁Bean
  7. 关闭容器

2.3 Bean的生命周期

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

Spring的一生其实也差不多是Bean 的一生吧~

Bean的生命周期,也是经典的面试题!

  • 这一部分讲的就比较细致,但是也是了解为主~

Bean的生命周期分为以下5大部分:

  1. 实例化Bean
    • 只是分配内存空间,现在Bean既没有初始化,而且还是游离在内存中的
  2. 设置属性
    • 进行依赖注入,将需要的但没有初始化的Bean对象注入到属性中,Bean不游离了
  3. Bean初始化
    • 流程较多,大概就是对Bean进行一系列的操作,然后Bean里面的值是有意义的
    • 其中就可能涉及Bean注入的属性
  4. 使用Bean
  5. 销毁Bean

2.3.1 Bean初始化

  1. 进行各种通知:如BeanNameAware、BeanFactoryAware…的接口方法
    • 就是暴露一个判断而已,就是告知你Bean的名字设置好了…
    • 至于你知道了这个通知后,进行什么逻辑就看你了~
    • 而系统也会自动去干一些事情~
  2. 初始化前置方法(前戏,准备)
  3. 执行初始化方法(设置就一定会执行,不设置就不会执行)
    • 注解的方式:@PostConstruct
    • xml的方式:init-method方法
  4. 初始化后置方法
    • 进行一些额外的操作和设置,以确保Bean在使用之前处于正确的状态
    • xml的方式:destroy-method的值
    • 注解的方式:@PreDestroy

2.3.2 Bean生命周期代码演示

在这里插入图片描述

  • 以这个实行了BeanNameAware接口的类为例

如图是注解的方式去定义初始化方法
在这里插入图片描述

如图是xml的方式去决定使用什么初始化方法

  • init-method的值对应的就是方法名,并且必须存在!

用注解设置多个初始化方法也更加方便~

在这里插入图片描述

  • 这是用注解的方式设置销毁Bean的方法

在这里插入图片描述

  • 这是用xml的方式设置销毁Bean的方法

对于初始化和销毁方法的设置,还有很多其他的方法!

  • 但是注解就是香!
  • xml的方式一次就一个

测试:

在这里插入图片描述

在这里插入图片描述

用子类,有更多的方法

在这里插入图片描述

在这里插入图片描述

获取Bean,使用Bean

在这里插入图片描述

扫描路径不要删掉,即使没用也要设置的

在这里插入图片描述

效果:

在这里插入图片描述

注解的优先级比较高~

顺序正如我们所料~

2.3.3 为什么属性设置比Bean初始化早

其实这个很容易想,例如一下操作:

在这里插入图片描述

如果user这个没有指向一块内存空间,只是null,那么就会空指针异常~

而实例化和属性注入之后,相当于在这里放了个箱子,之后的操作有了对象


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

Spring Core普通项目的讲解告一段落,接下来是Spring Boot的学习,敬请期待!

代码位置:SpringDemo4/src/main/java · 游离态/马拉圈2023年8月 - 码云 - 开源中国 (gitee.com)


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

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

相关文章

Shell脚本学习-应用启动脚本

利用系统函数模拟实现应用脚本启动的特殊颜色效果: /server/scripts/start_nginx.sh {start|stop|restart},用if语句实现。 [rootvm1 scripts]# cat start_nginx.sh #!/bin/bash. /etc/init.d/functionsUSAGE(){echo "USAGE: $0 {start|stop|resta…

DBeaver开源数据库管理工具发布23.1.3版本

导读DBeaver开源数据库管理软件近日发布了v23.1.3版本,该版本在空间数据查看器、数据传输、数据编辑器等多个模块进行了优化,提升了软件的可用性和兼容性。 具体来看,空间数据查看器新增了地图对象标记和曲线渲染支持,也实现了坐标复制等功能。数据传输模块增强了XLSX文件导入和…

探究LCS透明屏的工作原理

LCS透明屏是一种新型的显示技术,它能够在显示屏上实现透明效果,使得用户可以同时看到屏幕上的内容和背后的物体。这种技术在商业广告、展览、零售等领域有着广泛的应用前景。 LCS透明屏的工作原理是利用液晶分子的特性来控制光的透过与阻挡。 液晶分子可…

WebGPU重塑Web开发的未来

一、 WebGL 1.1 什么是WebGL 说到 WebGL,就不得不说说 OpenGL。在早期的个人电脑中,使用最广泛的 3D 图形渲染技术是 Direct3D 和 OpenGL。Direct3D 是微软 DirectX 技术的一部分,主要用于 Windows 平台。 OpenGL 作为一种开源的跨平台技术,赢得了众多开发者的青睐。 后…

ES6基础知识十:你是怎么理解ES6中 Decorator 的?使用场景?

一、介绍 Decorator,即装饰器,从名字上很容易让我们联想到装饰者模式 简单来讲,装饰者模式就是一种在不改变原类和使用继承的情况下,动态地扩展对象功能的设计理论。 ES6中Decorator功能亦如此,其本质也不是什么高大…

JavaData:JDK8之前传统的日期和时间

Data JDK8之前传统的日期和时间 //目标:掌握Date日期类的使用。 //1、创建一个Date的对象:代表系统当前时间信息的。 Date d new Date(); system.out.println(d);//2、拿到时间毫秒值。 long time d.getTime(); system.out.println(time);//3、把时间毫秒值转换成日期对象:2…

僵尸进程(Zombie process )及孤儿进程简介

1.僵尸进程如何产生? 僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占…

TCP连接的状态详解以及故障排查(四)

TCP连接的终止(四次握手释放) 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在…

玛氏宠物专访 | 宠物生意「狂飙」,品牌如何抢滩千亿宠食蓝海?

“两脚兽”不敌“四脚吞金兽”。 越来越多人加入“铲屎官”的行列,我国宠物市场规模数千亿,空间大、增速快,已是基本共识。宠物零食、宠物健康检测、宠物心理疗法、宠物美容、宠物社区、宠物智能喂养工具等等,从食品用品到服务&a…

Java工程师必备:全面解析Java生态知识图谱-打通工程师的成功之路

​​​​​​ 计算机基础知识 | |--- 数据结构与算法 |--- 操作系统 |--- 网络通信 |--- 数据库基础 Java SE(标准版) | |--- 语言基础 |--- 面向对象编程 |--- 集合框架 |--- IO流与NIO |--- 多线程与并发 |--- 反射与动态代理 |--- Lambda表达式 |---…

10个简单但很有用的Python装饰器

装饰器(Decorators)是Python中一种强大而灵活的功能,用于修改或增强函数或类的行为。装饰器本质上是一个函数,它接受另一个函数或类作为参数,并返回一个新的函数或类。它们通常用于在不修改原始代码的情况下添加额外的…

uni-app:实现表格多选及数据获取

效果&#xff1a; 代码&#xff1a; <template><view><scroll-view scroll-x"true" style"overflow-x: scroll; white-space: nowrap;"><view class"table"><view class"table-tr"><view class&quo…

探索Vue组件通信的秘密:打破隔阂,实现数据共享

一、Vue组件通信 每个组件都有自己的数据, 提供在data中, 每个组件的数据是独立的, 组件数据无法互相直接访问 (合理的)但是如果需要跨组件访问数据, 就需要用到组件通信 要是有一万个商品&#xff1f;&#xff1f;&#xff1f;&#xff1f;就要写一万个吗&#xff1f;函数调用…

DevExpress WPF Tree List组件,让数据可视化程度更高!(二)

DevExpress WPF Tree List组件是一个功能齐全、数据感知的TreeView-ListView混合体&#xff0c;可以把数据信息显示为REE、GRID或两者的组合&#xff0c;在数据绑定或非绑定模式下&#xff0c;具有完整的数据编辑支持。 在上文中&#xff08;点击这里回顾DevExpress WPF Tree …

【如何更加高效从容地管理应用程序安全?《Python全栈安全》告诉你】

安全是一个全栈性问题&#xff0c;包括用户接口、API、Web服务器、网络基础设施等。通过掌握强大的库、框架以及Python生态系统中的工具&#xff0c;你可自上而下地保护自己的系统。本书列举大量实例&#xff0c;插图清晰&#xff0c;代码丰富&#xff0c;准确地告诉你如何保护…

【javaSE】 抽象类

目录 抽象类概念 抽象类语法 抽象类特性 1. 抽象类不能直接实例化对象 2. 抽象方法不能是 private 的 3. 抽象方法不能被final和static修饰 4. 抽象类必须被继承&#xff0c;并且继承后子类要重写父类中的抽象方法 5. 抽象类中不一定包含抽象方法&#xff0c;但是有抽象…

k8s部署xxl-job分布式任务调度服务

一、背景 什么时候需要把xxl-job部署到k8s里 当你的java服务部署到K8S后&#xff0c;因为xxl-job的任务调度器需要对注册上来的执行器进行健康检测&#xff0c;而java服务作为执行器&#xff0c;注册地址是pod的Ip地址&#xff1b;所以&#xff0c;调度器想要访问执行器的网路…

自动化测试的生命周期是什么? qt

&#xfeff;Java版知识付费源码 Spring CloudSpring BootMybatisuniapp前后端分离实现知识付费平台 提供职业教育、企业培训、知识付费系统搭建服务。系统功能包含&#xff1a;录播课、直播课、题库、营销、公司组织架构、员工入职培训等。 提供私有化部署&#xff0c;免费售…

台式机/工控机通过网线共享笔记本电脑无线网络linux系统下 usb网卡的驱动安装

一、台式机/工控机通过网线共享笔记本电脑无线网络 1、 将台式机通过网线和笔记本连接。 2、 将笔记本的“本地连接”和“无线网络连接”的ipv4均设置为自动获取。 4.修改台式机的IP地址为如下&#xff08;对应笔记本信息&#xff09; IP地址为192.168.XXX.12 子网掩码为255.2…

JavaSE【继承、初始化、pretected封装、组合】

一、继承 继承 (inheritance) 机制 &#xff1a;是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特 性 的基础上进行扩展&#xff0c;增加新功能 &#xff0c;这样产生新的类&#xff0c;称 派生类 。 继承呈现了面向对象程序设计的层次结…