Spring学习(四):Scope的介绍及其失效解决方案
目录
一、spring当中有哪些scope
二、scope初始化与销毁演示
2.1 scope的初始化
2.2 scope的销毁
三、scope失效及其解决方案
3.1 scope失效演示
3.2 scope失效解决方案一:@Lazy
3.3 scope失效解决方案二:设置proxyMode属性
3.4 scope失效解决方案三:ObjectFactory
3.5 scope失效解决方案四:ApplicationContext容器
3.6 总结
一、spring当中有哪些scope
我使用的spring版本是5.3.10,其中scope有五种:
-
singleton:从spring中获取bean时,每次获取的是同一个bean
-
prototype:从spring中获取bean时,每次获取的是新的bean
-
request:生成的bean存活于request域中,生命周期也与request相同
-
session:生成的bean存活于session域中,生命周期也与session相同
-
application:生成的bean存活于application域中,生命周期也与application相同(spring中的application指的是servletContext)
二、scope初始化与销毁演示
2.1 scope的初始化
主启动类:
@SpringBootApplication
public class A08 {public static void main(String[] args) {SpringApplication.run(A08.class, args);}
}
主启动类启动后,就会扫描到下面的三个bean:
@Scope("request")
@Component
public class BeanForRequest {private static final Logger log = LoggerFactory.getLogger(BeanForRequest.class);@PreDestroypublic void destroy() {log.debug("destroy");}
}
@Scope("session")
@Component
public class BeanForSession {private static final Logger log = LoggerFactory.getLogger(BeanForSession.class);@PreDestroypublic void destroy() {log.debug("destroy");}
}
@Scope("application")
@Component
public class BeanForApplication {private static final Logger log = LoggerFactory.getLogger(BeanForApplication.class);@PreDestroypublic void destroy() {log.debug("destroy");}
}
这三个bean在controller中被用到:
@RestController
public class MyController {//MyController是单例,单例去使用其他的域,都要加@Lazy,否则会失效@Lazy@Autowiredprivate BeanForRequest beanForRequest;@Lazy@Autowiredprivate BeanForSession beanForSession;@Lazy@Autowiredprivate BeanForApplication beanForApplication;@GetMapping(value = "/test", produces = "text/html")public String test(HttpServletRequest request, HttpSession session) {ServletContext sc = request.getServletContext();String sb = "<ul>" +"<li>" + "request scope:" + beanForRequest + "</li>" +"<li>" + "session scope:" + beanForSession + "</li>" +"<li>" + "application scope:" + beanForApplication + "</li>" +"</ul>";return sb;}
}
打开不同的浏览器, 刷新 http://localhost:8080/test 即可查看效果。如果 jdk > 8, 运行时请添加 --add-opens java.base/java.lang=ALL-UNNAMED
打开一个浏览器(例如:Chrome)可以发现,每次刷新都可以看到request域的bean不一样,说明每次创建的是新的bean,request的bean会在请求结束后销毁。
再打开一个浏览器(例如:edge)可以发现,会话域的bean也不同,是因为每个浏览器都会创建自己的会话。

打开不同的浏览器也能看到,request和session的bean不相同,是因为每个浏览器都有自己的请求和会话域;而application的bean时相同的,因为他们对应的是同一个web应用程序

2.2 scope的销毁
-
singleton,容器启动时创建(未设置延迟),容器关闭时销毁
-
prototype,每次使用时创建,不会自动销毁,需要调用DefaultListableBeanFactory.destroyBean(bean) 销毁
-
request,每次请求用到此 bean 时创建,请求结束时销毁
-
session,每个会话用到此 bean 时创建,会话结束时销毁
-
application,web 容器用到此 bean 时创建,容器停止时销毁
在浏览器中每次刷新我们都可以看到控制台打印出了beanForRequest的销毁方法,这是因为每次刷新都代表着一个请求结束了;session销毁时间默认为30min,为了方便演示,我们在application.properties文件中设置
server.servlet.session.timeout=10s
这样session就可以在1min后自动销毁了(spring内部设置session销毁时间低于1min就视为1min,这篇文章剖析了这部分源码:SpringBoot设置Session失效时间 - 简书),我们可以在控制台上看到session销毁的日志
三、scope失效及其解决方案
3.1 scope失效演示
以单例注入多例为例(单例注入其他类型的scope也是同理),先看看主启动类:
@ComponentScan("com.itheima.a08.sub")
public class A08_1 {private static final Logger log = LoggerFactory.getLogger(A08_1.class);public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A08_1.class);E e = context.getBean(E.class);log.debug("{}", e.getF1().getClass());log.debug("{}", e.getF1());log.debug("{}", e.getF1());log.debug("{}", e.getF1());context.close();}
}
在主启动类中,我们先通过getBean方法拿到E的对象,再通过get方法拿到e中注入的f1对象。E并没有加@prototype注解,所以默认是个单例,而f1是个多例。
@Component
public class E {@Autowiredprivate F1 f1;public F1 getF1() {return f1;}
}
@Scope("prototype")
@Component
public class F1 {
}
那么问题来了,我们在主启动类中多调用几次,每次返回的f1对象是同一个对象还是不同对象?我们既然将F1标注为多例,自然是期望返回不同对象的。
然而运行可得,每次返回的都是同一对象 :

原因是:对于单例对象来讲,依赖注入仅发生一次,后续再没有发生依赖注入,E再没有用到多例的F1,因此E用的始终是第一次依赖注入的F1。
3.2 scope失效解决方案一:@Lazy
我们在成员变量或者使用的方法上加上@Lazy注解,@Lazy能够帮助我们生成代理对象,这样,代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的f1对象。

@Component
public class E {@Lazy@Autowiredprivate F1 f1;public F1 getF1() {return f1;}
}
运行发现每次生成的bean已经不一样了。我们也打印一下e.getF1().getClass,看看生成的F1的真实类型,可以看到并不是F1,而是代理增强的类。
3.3 scope失效解决方案二:设置proxyMode属性
我们还可以在被调用的多例类上设置 proxyMode 属性,我们用F2来演示这个解决办法:
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}
这个方法的本质也是生成代理。运行后可以看到,生成的bean也不一样了,获取到的F2的真实类型也是代理增强的类。
3.4 scope失效解决方案三:ObjectFactory
我们可以在E中注入的时候将F声明为 ObjectFactory 类型,这样每次获取的时候都由工厂生成不同的F。我们用F3来演示这个解决办法:
@Component
public class E {@Autowiredprivate ObjectFactory<F3> f3;public F3 getF3() {return f3.getObject();}
}
@Scope("prototype")
@Component
public class F3 {
}
3.5 scope失效解决方案四:ApplicationContext容器
直接实现容器,利用容器的getBean方法来获取F多例bean。我们用F4来演示:
@Component
public class E {@Autowiredprivate ApplicationContext context;public F4 getF4() {return context.getBean(F4.class);}
}
@Scope("prototype")
@Component
public class F4 {
}
3.6 总结
虽然上述四种方法各不相同,但理念基本相同,都是延迟其他scope bean的获取。他们都是不直接获取多例,而是在中间加一个对象,通过这个对象等到运行时再去获取多例bean
更推荐使用BeanFactory 或 ApplicationContext,因为更加简洁,且不像代理一样会造成一定的性能损耗。
相关文章:
Spring学习(四):Scope的介绍及其失效解决方案
目录 一、spring当中有哪些scope 二、scope初始化与销毁演示 2.1 scope的初始化 2.2 scope的销毁 三、scope失效及其解决方案 3.1 scope失效演示 3.2 scope失效解决方案一:Lazy 3.3 scope失效解决方案二:设置proxyMode属性 3.4 scope失效解决…...
【学习集合--Set】
学习内容: Set集合概述Set集合实现—HashSet LinkedHashSet和TreeSet 学习产出: Set集合概述 Set中不存在值相同的节点。将两个对象e1.equals(e2),如果结果为true,或者(e1e2)内存地址相等,就认为两个对象…...
函数的参数
函数的默认实参 函数默认参数:函数的形参可以有默认值,如果我们自己传入参数,就用自己的数据,如果没有,那么用默认值 特别注意*: 如果某个位置有了默认参数,那么从这个位置往后,必…...
数组(八)-- LC[53][152] 最大子数组之和与乘积最大子数组
1 最大子数组之和 1.1 题目描述 题目链接:https://leetcode.cn/problems/maximum-subarray/ 1.2 求解思路 1. 暴力法 class Solution:def maxSubArray(self, nums: List[int]) -> int:length len(nums)max_sum float(-inf)for i in range(length):sum_sub_…...
docker2-zabbix
安装最新版docker yum remove docker docker-common docker-selinux docker-engine yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum makecache fast yum list docker-ce --showduplicates | sort -r yum install docke…...
ctcdecode安装
1.下载 https://pan.baidu.com/s/1sZMbzzYtBoT35zHtDifVqQ ,提取码:a05y。然后解压到ctcdecode文件夹中。 感谢 ctcdecode安装_huangneng0219的博客-CSDN博客 提供。 然后build.py文件中的compile_args [-O3, -DKENLM_MAX_ORDER6, -stdc11, -fPIC] …...
虚树学习小记
虚树是什么 虚树指在原树上选择需要的点和它们的LCALCALCA组成的一棵树。这样可以使在树DP时顶点数更少,从而减少时间复杂度。一般用于有多组数据且能保证所有数据访问的点的和不超过规定范围。 情景代入:SDOI2011消耗战 SDOI2011消耗战 题目大意 给…...
【C++】特殊类设计(单例模式)
文章目录一、设计模式概念二、设计一个不能被拷贝的类三、设计一个只能在堆上创建对象的类3.1 私有构造3.2 私有析构四、设计一个只能在栈上创建对象的类五、设计不能被继承的类六、单例模式❗️❗️6.1 饿汉模式6.2 懒汉模式6.2.1 线程安全问题6.2.2 新写法一、设计模式概念 …...
基于YOLOv5的水下海洋目标检测
摘要:水下海洋目标检测技术具有广泛的应用前景,可以用于海洋环境监测、海洋资源开发、海洋生物学研究等领域。本文提出了一种基于 YOLOv5 的水下海洋目标检测方法,使用数据增强方法进行了大量实验,并与其他方法进行了对比…...
磁盘这列(Raid)
RAID介绍 RAID技术通过把多个硬盘设备组合成一个容量更大的、安全性更好的磁盘阵列。把数据切割成许多区段后分别放在不同的物理磁盘上,然后利用分散读写技术来提升磁盘阵列整体的性能,同时把多个重要数据的副本同步到不同的物理设备上,从而…...
Oracle之PL/SQL存储过程与函数练习题(七)
1.创建一个存储过程,以员工号为参数,输出该员工的工资2.创建一个存储过程,以员工号为参数,修改该员工的工资。若该员工属于10号部门,则工资增加150;若属于20号部门,则工资增加200;若…...
C++入门教程||C++ 基本的输入输出||C++ 数据结构
C 基本的输入输出 C 基本的输入输出 C 标准库提供了一组丰富的输入/输出功能,我们将在后续的章节进行介绍。本章将讨论 C 编程中最基本和最常见的 I/O 操作。 C 的 I/O 发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、…...
线性表——顺序表
文章目录一:线性表二:顺序表1:概念与结构1:静态顺序表2:动态顺序表2:动态顺序表的代码实现1:结构2:接口实现1:初始化2:释放内存3:检查容量4&#…...
第六章 Vite4+Vue3+Vtkjs 模型颜色切换、漫反射曲面颜色
一、介绍 💥 💥 Vtk里面工具非常的齐全,但是相关的文档又少之又少,只能花大量时间去阅读源码。漫反射曲面颜色是什么意思呢,Vtk可以使用漫反射曲面颜色来模拟光线在表面反射时的颜色。漫反射是一种光线与表面发生碰撞后,被散射到各个方向的现象,这种现象可以用来解释物…...
【QT学习七】QTreeWidget
目录 一、QTreeWidget 概述 二、QTreeWidget 的基本使用 2.1、创建 QTreeWidget 控件 2.2、设置 QTreeWidget 的大小和位置 2.3、设置 QTreeWidget 的列数和列标题 2.4、添加节点 2.5、读取节点 2.6、设置节点数据 2.7、自定义节点样式 三、注意事项 四、完整示例 一…...
【Linux】组管理和权限管理
目录1 Linux组的基本介绍2 文件/目录所有者2.1 查看文件的所有者2.2 修改文件所有者3 组的创建3.1 基本指令3.2 应用实例4 文件/目录 所在组4.1 查看文件/目录所在组4.2修改文件/目录所在的组5 其他组6 改变用户所在组6.1 改变用户所在的组6.2 应用实例7 权限介绍8 rwx权限详解…...
从零到一发布 NPM 包
如果你负责前端的基础能力建设,发布各种功能/插件包犹如家常便饭,所以熟悉对 npm 包的发布与管理是非常有必要的,故此有了本篇总结文章。本篇文章一方面总结,一方面向社区贡献开箱即用的 npm 开发、编译、发布、调试模板ÿ…...
uniapp国际化配置
1、创建资源文件 创建一个locale文件夹,新增index.js,en.json,zh-hans.json 2.配置locale文件夹中的index.js文件 import Vue from vue import VueI18n from vue-i18n// v8.x import en from ./en.json import zhHans from ./zh-Hans.json import zhHant from .…...
前端中 try-catch 捕获不到哪些异常和常见错误
在开发过程中,我们的目标是 0error,0warning。 但有很多因素并不是我们可控的,为了避免某块代码的错误,影响到其他模块或者整体代码的运行,我们经常会使用try-catch模块来主动捕获一些异常或者错误。 比如我们在获取…...
javaEE 初阶 — 如何构造一个 HTTP 请求
文章目录使用 form 表单标签构造1 构造 GET 请求2 构造 POST 请求使用 ajax 构造1 什么是异步2 代码中如何使用 ajax使用第三方工具构造1 postman 工具的安装2 postman 工具的使用使用 form 表单标签构造 1 构造 GET 请求 使用 form 表单构造 HTTP 请求,需要用到两…...
3步打造Windows桌面美学:TranslucentTB让任务栏焕发新生
3步打造Windows桌面美学:TranslucentTB让任务栏焕发新生 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 一、为什么你的任务栏…...
避坑指南:深度相机与RGB相机标定中的5个常见错误
避坑指南:深度相机与RGB相机标定中的5个常见错误 在三维重建和增强现实开发中,深度相机与RGB相机的联合标定是基础却极易出错的关键环节。许多开发者投入大量时间调试标定结果,却因忽视了一些看似简单的细节而功亏一篑。本文将揭示五个最常被…...
Linux党福利:Debian12下用VSCode+SDCC玩转51单片机(含WSL配置指南)
Debian 12下构建开源51单片机开发环境:VSCodeSDCC全攻略 在Linux环境下开发51单片机一直是个小众但极具技术挑战性的选择。相比Windows平台上Keil的垄断地位,开源工具链在Linux上的表现往往被低估。本文将带你用VSCodeSDCC在Debian 12上搭建一个完整的51…...
ARM Cortex-M0 SoC实战:如何用SystemVerilog和C语言实现软硬件高效握手通信
ARM Cortex-M0 SoC实战:软硬件握手通信的黄金法则 在嵌入式系统开发中,处理器与外围设备之间的高效通信一直是工程师们面临的挑战。当ARM Cortex-M0这类精简指令集处理器遇到AHB-Lite总线时,如何设计出既稳定又高效的握手协议?本…...
掌握LSLib:解锁《神界原罪》与《博德之门3》MOD制作的神器
掌握LSLib:解锁《神界原罪》与《博德之门3》MOD制作的神器 【免费下载链接】lslib Tools for manipulating Divinity Original Sin and Baldurs Gate 3 files 项目地址: https://gitcode.com/gh_mirrors/ls/lslib LSLib是一个功能强大的开源工具集࿰…...
Qwen3-TTS开源模型教程:Gradio接口封装+API服务发布完整指南
Qwen3-TTS开源模型教程:Gradio接口封装API服务发布完整指南 1. 前言:为什么你需要一个专属的语音合成服务? 想象一下,你正在开发一个智能客服应用,需要为不同国家的用户提供多语言的语音回复;或者你是一个…...
DAMOYOLO-S惊艳效果案例集:多领域高难度场景检测展示
DAMOYOLO-S惊艳效果案例集:多领域高难度场景检测展示 今天咱们不聊枯燥的理论和复杂的部署,直接来看点“硬货”。如果你正在寻找一个能在各种刁钻场景下都表现稳定的目标检测模型,那么DAMOYOLO-S绝对值得你花几分钟了解一下。它不是什么新概…...
遥感小白别慌!ENVI 5.6 基础操作保姆级教程:从打开文件到剖面图显示,一篇搞定
遥感新手实战指南:ENVI 5.6 从零到剖面分析的完整工作流 第一次打开ENVI时,那个布满英文按钮的界面和密密麻麻的菜单栏,是不是让你瞬间想起了大学时被专业课支配的恐惧?别担心,三年前的我也是这样——面对一幅Landsat…...
ESP32驱动MT6826S磁编码器:从接线防烧到实时速度计算(附完整Arduino库)
ESP32与MT6826S磁编码器实战指南:安全接线与高效数据采集 1. 硬件连接:避开那些可能毁掉你项目的陷阱 MT6826S磁编码器作为一款高精度角度测量器件,在机器人关节控制、无人机云台稳定等场景中表现优异。但许多开发者第一次接触这款编码器时&a…...
AI赋能软件测试:基于PyTorch视觉模型实现自动化GUI测试脚本生成效果演示
AI赋能软件测试:基于PyTorch视觉模型实现自动化GUI测试脚本生成效果演示 1. 效果亮点预览 想象一下这样的场景:一个AI系统正在自动测试你的软件界面,它能像人类测试工程师一样"看"懂屏幕上的每个元素,发现那些传统脚本…...
