news 2026/7/10 9:17:00

教程:Bean作用域作者:太虚野老

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
教程:Bean作用域作者:太虚野老

目录

说明: 3

Bean作用域 4

singleton作用域 4

prototype作用域 5

具有原型Bean依赖的单例Bean 7

Request, Session, Application, 和 WebSocket 作用域 7

初始网络配置 7

request作用域 8

session作用域 8

application作用域 9

websocket作用域 9

作用域 Bean 作为依赖项 9

选择要创建的代理类型 11

直接注入Request/Session引用 11

自定义作用域 11

创建自定义作用域 11

使用自定义作用域 12

附录一:原型作用域(Prototype)测试代码 13

附录二:具有原型Bean依赖的单例Bean测试代码 16

附录三:四个web作用域测试代码 19

1、@RequestScope 19

2、@SessionScope 21

3、@ApplicationScope 25

4、@WebSocketScope 28

附录四:作用域 Bean 作为依赖项测试代码 40

附录五:演示ObjectFactory的作用 43

附录六:演示ObjectProvider的作用 48

附录七:火狐浏览器清除任意网站的 Cookie 55

说明:

1.Spring Framework版本:7.0.6

2.开发框架:Spring boot(版本4.0.5)

3.开发工具:eclipse 2025-09 (4.37.0)

4.jdk版本:25

5.操作系统:debian12

Bean作用域

当你创建一个bean定义时,你实际上是在为创建由该bean定义所定义的类的实际实例制定一个配方。bean定义是配方的概念很重要,因为这意味着,就像使用一个类一样,你可以根据一个配方创建出许多对象实例。

您不仅可以控制从特定bean定义创建的对象中要插入的各种依赖项和配置值,还可以控制从特定bean定义创建的对象的作用域。这种方法功能强大且灵活,因为您可以通过配置来选择所创建对象的范围,而不必在Java类级别上硬性规定对象的范围。Bean 可以被定义部署在多个作用域中的任意一个。Spring Framework 支持六个作用域,其中四个仅在使用支持 Web 的 ApplicationContext 时可用。您还可以创建自定义作用域。

下表描述了支持的作用域:

Table 1. Bean scopes

作用域

描述

singleton

(默认)将单个Bean定义的作用域限定为每个Spring IoC容器中的一个对象实例。

prototype

将单个Bean定义作用域扩展到任意数量的对象实例。

request

将单个Bean定义的作用域限定在单个HTTP请求的生命周期内。也就是说,每个HTTP请求都会根据单个Bean定义创建自己的Bean实例。仅在支持Web的Spring ApplicationContext上下文中有效。

session

将单个Bean定义的作用域限定在HTTP Session的生命周期内。仅在支持Web的Spring ApplicationContext上下文中有效。

application

将单个Bean定义的作用域限定在ServletContext的生命周期内。仅在支持Web的SpringApplicationContext上下文中有效。

websocket

将单个Bean定义的作用域限定在WebSocket的生命周期内。仅在支持Web的Spring ApplicationContext上下文中有效。

注意:

线程作用域可用,但默认情况下未注册。有关更多信息,请参阅SimpleThreadScope的文档。有关如何注册此作用域或任何其他自定义作用域的说明,请参阅使用自定义作用域。

singleton作用域

只有一个单例Bean的共享实例受到管理,对于具有与该Bean定义匹配的一个或多个ID的Bean的所有请求,都会导致Spring容器返回该特定的Bean实例。

换言之,当你定义一个 bean 定义并且其作用域为单例时,Spring IoC 容器会为该 bean 定义所定义的对象创建一个实例。这个单一实例存储在这样一个单例Bean的缓存中,所有后续对该命名Bean的请求和引用都会返回缓存的对象。下图展示了单例作用域的工作原理:

Spring中的单例Bean概念与《四人组(GoF)模式》一书中所定义的单例模式有所不同。GoF 单例模式对对象的范围进行了硬编码,使得每个ClassLoader(类加载器)只能创建一个且只能创建一个特定类的实例。Spring 单例的作用域最好描述为容器内和 bean 内。这意味着,如果你在单个Spring容器中为某个特定类定义了一个bean,那么Spring容器将创建该bean定义所定义的类的一个且仅一个实例。在Spring中,单例作用域是默认的作用域。要在XML中将一个bean定义为单例,可以按照以下示例定义一个bean:

<bean/> <!-- 以下内容是等价的,但有些冗余(默认作用域为单例) --> <bean scope="singleton"/>

prototype作用域

在 bean 部署中,非单例原型作用域会导致每次请求特定 bean 时都会创建一个新的 bean 实例。也就是说,当将该 bean 注入到另一个 bean 中,或者通过在容器上调用getBean()方法请求该 bean 时,都会如此。通常,您应该将所有有状态的 bean 使用原型作用域,将无状态的 bean 使用单例作用域。

下图展示了Spring原型作用域:

数据访问对象(DAO)通常不配置为原型,因为典型的DAO不包含任何会话状态。对我们来说,重用单例图的核心部分更容易。)

以下示例在XML中将一个bean定义为原型:

<bean scope="prototype"/>

与其他作用域相比,Spring 并不管理原型 bean 的完整生命周期。容器会实例化、配置并以其他方式组装原型对象,然后将其交给客户端,而不再保留该原型实例的任何记录。因此,尽管初始化生命周期回调方法会在所有对象上调用,而不考虑其作用域,但在原型的情况下,配置的销毁生命周期回调方法则不会被调用。客户端代码必须清理原型作用域内的对象,并释放原型Bean占用的昂贵资源。要让Spring容器释放原型作用域Bean占用的资源,可以尝试使用一个自定义Bean后处理器,该处理器持有需要清理的Bean的引用。

在某些方面,Spring容器在原型作用域Bean中的作用相当于Java new操作符的替代品。此后所有的生命周期管理都必须由客户端处理。(有关Spring容器中bean生命周期的详细信息,请参阅生命周期回调。)

注:

  • 每一次@Autowired注入都会生成一个全新不同的实例,单例作用域除外。

  • 每次依赖注入 / 每次 getBean () 都新建对象

  • 永不自动销毁

  • Spring容器本身不会保存任何原型 Bean 实例引用!

  • 触发销毁方法的两种方法:

    • 使用DisposableBean接口(原生销毁接口)。不用注解,实现接口就行

    • 调用ConfigurableBeanFactory.destroyBean(beanName,beanInstance)@PreDestroy依然生效,必须保留

    • 触发销毁方法的两种方法测试代码详见附录一。

  • 想要每次调用都拿到全新原型,不能直接字段注入,要用:ObjectProvider<Bean>或者ApplicationContext.getBean(),或者ConfigurableBeanFactory.getBean()也可以。

@Autowired private ObjectProvider<ProtoBean> provider; public void getNew(){ ProtoBean b1 = provider.getObject(); ProtoBean b2 = provider.getObject(); // b1 != b2 }

具有原型Bean依赖的单例Bean

当您使用具有原型Bean依赖的单例作用域Bean时,请注意依赖是在实例化时解析的。因此,如果你将一个原型作用域的Bean依赖注入到一个单例作用域的Bean中,一个新的原型Bean将被实例化,然后被依赖注入到单例Bean中。这个原型实例是唯一提供给单例作用域Bean的实例。

然而,假设您希望单例作用域的Bean在运行时反复获取原型作用域Bean的新实例。你不能将原型作用域的Bean依赖注入到单例Bean中,因为这种注入只在Spring容器实例化单例Bean并解析和注入其依赖项时发生一次。如果你在运行时需要多次获取原型Bean的新实例,请参阅方法注入。

测试代码详见附录二。

Request, Session, Application, 和 WebSocket 作用域

只有在使用支持 Web 的 Spring ApplicationContext 实现(如 XmlWebApplicationContext)时,request,session,applicationwebsocket作用域才可用。如果你将这些作用域与常规的Spring IoC容器(如ClassPathXmlApplicationContext)一起使用,则会抛出一个IllegalStateException,指出存在未知的Bean作用域。

四个 Web作用域的测试代码详见附录三。

初始网络配置

为了支持在request,session,applicationwebsocket(Web范围Bean)对Bean的范围界定,在定义Bean之前需要进行一些初步的简单配置。(对于标准范围:单例和原型,则不需要进行此初始设置。)

如何完成这一初始设置取决于你特定的Servlet环境。

如果你在Spring Web MVC中访问作用域Bean,实际上是在Spring DispatcherServlet处理的请求中,无需进行特殊设置。DispatcherServlet已经公开了所有相关状态。

如果你使用一个Servlet Web容器,且请求是在Spring的DispatcherServlet之外处理的(例如,在使用JSF时),那么你需要注册org.springframework.web.context.request.RequestContextListener这个ServletRequestListener。这可以通过使用WebApplicationInitializer接口以编程方式实现。或者,将以下声明添加到您的Web应用程序的web.xml文件中:

<web-app> ... <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> ... </web-app>

或者,如果您的监听器设置存在问题,可以考虑使用Spring的RequestContextFilter。该过滤器的映射依赖于周围的Web应用程序配置,因此您必须根据实际情况进行更改。以下清单显示了Web应用程序的过滤器部分:

<web-app> ... <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app>

DispatcherServlet、RequestContextListener和RequestContextFilter都做着完全相同的事情,即将HTTP请求对象绑定到处理该请求的线程上。这使得请求作用域和会话作用域的Bean在调用链的下游也可用。

request作用域

考虑以下用于 bean 定义的 XML 配置:

<bean scope="request"/>

Spring容器会为每个HTTP请求使用loginAction bean的定义来创建一个新的LoginAction bean实例。也就是说,loginAction bean的作用域是在HTTP请求级别。你可以随意更改所创建实例的内部状态,因为从同一loginAction bean定义创建的其他实例看不到这些状态变化。它们特定于单个请求。当请求处理完毕后,作用域仅限于该请求的Bean将被丢弃。

在使用注解驱动组件或Java配置时,可以使用@RequestScope注解将组件分配给请求作用域。以下示例展示了如何执行此操作:

@RequestScope @Component public class LoginAction { // ... }

Request作用域 Bean销毁时机:在一次 HTTP 请求处理完全结束、响应返回客户端 之后,立刻销毁。

session作用域

考虑以下用于 bean 定义的 XML 配置:

<bean scope="session"/>

Spring容器在单个HTTP会话的生命周期内,通过使用userPreferences bean的定义来创建UserPreferences bean的新实例。换言之,userPreferences bean的作用域实际上是在HTTPSession级别。与请求作用域的Bean一样,您可以随意更改所创建实例的内部状态,因为其他同样使用从同一userPreferences Bean定义创建的实例的HTTP Session实例看不到这些状态更改,因为这些更改特定于单个HTTP Session。当HTTP Session最终被丢弃时,作用域限定在该特定HTTP Session内的Bean也会被丢弃。

在使用注解驱动组件或Java配置时,您可以使用@SessionScope注解将组件分配到会话作用域。

@SessionScope @Component public class UserPreferences { // ... }

session作用域bean在会话结束后不会立即销毁,要等到时间到期后销毁。除非立即调用HttpSession的invalidate()方法。

application作用域

考虑以下用于 bean 定义的 XML 配置:

<bean scope="application"/>

Spring 容器会根据 appPreferences 的 bean 定义在整个 Web 应用程序中仅创建一次 AppPreferences 类的新实例。也就是说,appPreferences bean的作用域是ServletContext级别,并作为常规的ServletContext属性进行存储。这在一定程度上类似于Spring的单例bean,但在两个重要方面有所不同: 它是一个针对每个ServletContext的单一实例,而不是针对每个Spring ApplicationContext(在任何给定的Web应用程序中可能存在多个)的单一实例,并且它实际上作为ServletContext的属性被公开,因此是可见的。

在使用注解驱动组件或Java配置时,您可以使用@ApplicationScope注解将组件分配到application作用域。以下示例展示了如何操作:

@ApplicationScope @Component public class AppPreferences { // ... }

websocket作用域

WebSocket作用域与WebSocket会话的生命周期相关联,并适用于基于WebSocket的STOMP应用,更多详情请参阅WebSocket作用域。

作用域 Bean 作为依赖项

Spring 的 IoC 容器不仅管理您的对象(即 bean)的实例化,还负责将协作对象(或依赖项)连接起来。如果您想将(例如)具有 HTTP 请求作用域的 bean 注入到作用域更长的另一个 bean 中,您可以选择注入一个 AOP 代理来替代该作用域的 bean。也就是说,您需要注入一个代理对象,该对象公开与作用域对象相同的公共接口,但还能从相关作用域(例如 HTTP 请求)中检索出真正的目标对象,并将方法调用委托给该真实对象。

注意:

您还可以在作用域为单例的Bean之间使用<aop:scoped-proxy/>,这样引用就会通过一个可序列化的中间代理,从而能够在反序列化时重新获取目标单例Bean。

当对原型作用域的Bean声明<aop:scoped-proxy/>时,对共享代理的每次方法调用都会创建一个新的目标实例,然后将调用转发到该实例。

此外,作用域代理并不是以生命周期安全的方式从较短作用域访问Bean的唯一方法。您还可以将注入点(即构造函数、setter方法参数或自动注入字段)声明为ObjectFactory<MyTargetBean>

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/10 9:13:46

如何从点云数据快速重建高质量3D网格模型:Point2Mesh完全指南

如何从点云数据快速重建高质量3D网格模型&#xff1a;Point2Mesh完全指南 【免费下载链接】point2mesh Reconstruct Watertight Meshes from Point Clouds [SIGGRAPH 2020] 项目地址: https://gitcode.com/gh_mirrors/po/point2mesh 你是否曾经面对一堆杂乱无章的点云数…

作者头像 李华
网站建设 2026/7/10 9:09:43

Ubuntu安装OBS Studio完整指南:PPA安装、Wayland适配与树莓派优化

1. 为什么一个刚装好Ubuntu的人&#xff0c;第一件事不该急着开直播——但OBS Studio确实是绕不开的“真香”入口你刚在笔记本或树莓派上刷完Ubuntu 22.04 LTS&#xff0c;桌面干干净净&#xff0c;终端窗口还泛着幽幽蓝光。这时候最常被问到的问题不是“怎么连Wi-Fi”&#xf…

作者头像 李华
网站建设 2026/7/10 9:09:04

如何5分钟掌握百度网盘极速下载:智能解析工具实战指南

如何5分钟掌握百度网盘极速下载&#xff1a;智能解析工具实战指南 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 还在为百度网盘的缓慢下载速度而烦恼吗&#xff1f;当你急需…

作者头像 李华
网站建设 2026/7/10 9:08:53

Meta Muse Image:零门槛AI图像生成在社交平台的应用与对比

Meta 最新推出的 Muse Image 图像生成模型已经正式集成到 Instagram 和 WhatsApp 中&#xff0c;用户可以直接在聊天或发帖时使用 AI 生成图像。与之前需要单独访问的 AI 绘画工具不同&#xff0c;Muse Image 的亮点在于完全免费、无需下载额外应用&#xff0c;直接在社交平台内…

作者头像 李华