当前位置: 首页 > news >正文

教程: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>

http://www.cnnetsun.cn/news/3260215.html

相关文章:

  • 达芬奇免费版与Studio版对比:硬件要求、下载安装与性能优化指南
  • 如何从点云数据快速重建高质量3D网格模型:Point2Mesh完全指南
  • 阴阳师自动化脚本:5步解决模拟器适配问题,让百鬼夜行稳定运行
  • Ubuntu安装OBS Studio完整指南:PPA安装、Wayland适配与树莓派优化
  • 如何5分钟掌握百度网盘极速下载:智能解析工具实战指南
  • Meta Muse Image:零门槛AI图像生成在社交平台的应用与对比
  • DAZ Studio 4.10简体中文版安装深度解析:非标汉化与系统级适配
  • 从零上手硅基流动API:密钥获取、环境配置与Python调用实战
  • Cursor AI生成HTML页面的7个致命误区:92%开发者踩坑的隐藏陷阱与绕过方案
  • 告别复制粘贴!MouseTooltipTranslator:一键悬停翻译,让语言障碍瞬间消失
  • ROS四轴机械臂的搭建
  • 2026年GEO监测行业趋势与工具选型深度报告
  • SpatialBoost:语言引导增强视觉预训练模型的三维空间感知能力
  • Wink窗口管理器2026保姆级安装与工作流配置指南
  • AI图片生成提示词应该怎么写?
  • STM32上拉下拉电阻配置与DTH-08模块应用指南
  • PN结伏安特性曲线实测:Si/Ge二极管死区电压与温度系数对比分析
  • AI工程必备的11个Docker镜像实战指南
  • 从手动秒光到自动抢票:如何用Python脚本解决演唱会门票难题
  • 仅限首批读者|Claude Code私有部署脚本生成器(CLI工具v1.2)开源前内部测试版限时领取
  • 计算机毕业设计之社会福利保障系统
  • C++17 元编程状态机 fsm-cxx 实战:5分钟构建线程安全事件驱动模型
  • 《摸鱼王》插件 vs 浏览器原生阅读模式:2种隐蔽阅读方案对比评测
  • 2026年 Codex 中转站哪家好?API中转站推荐与接入避坑
  • Triton+KServe构建高可用ML模型服务化实战
  • 为什么92%的企业GPTs在商店上架后30天内下架?——GPTs审核机制逆向工程与过审加速器
  • STM32 寻迹小车 3种传感器布局对比:TCRT5000 vs 灰度 vs 摄像头
  • 大数据计算机毕设之基于 Django 的网课学习行为聚类分析系统的设计与实现 基于 Django 的线上教育热度趋势大数据监测系统(完整前后端代码+说明文档+LW,调试定制等)
  • STM32F103 FSMC 驱动 ILI9341 LCD:CubeMX 配置 3 个关键时序参数详解
  • Multisim 14.2 四人抢答器仿真:74LS175 芯片验证与 1kHz 时钟信号配置