探秘Spring Bean的秘境:作用域篇【beans 三】

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

探秘Spring Bean的秘境:作用域篇【beans 三】

    • 前言
    • 单例作用域
      • 如何声明单例Bean:
      • 特点:
    • 原型作用域
      • 如何声明原型Bean:
      • 特点:
    • 会话作用域
      • 如何声明会话作用域Bean:
      • 特点:
    • 请求作用域
      • 如何声明请求作用域Bean:
      • 特点:
    • 自定义作用域
    • 作用域的生命周期
      • 单例作用域:
      • 原型作用域:
      • 影响:
    • 实际应用场景
      • 1. 单例作用域(Singleton Scope):
      • 2. 原型作用域(Prototype Scope):
      • 3. 会话作用域(Session Scope):
      • 4. 请求作用域(Request Scope):

前言

在软件开发的舞台上,每个角色都有其独特的作用。Spring框架中的Bean也一样,通过作用域的不同,它们可以在应用中扮演不同的角色。从独一无二的单例到即时生成的原型,Spring的作用域机制为我们提供了丰富的选择。在这篇文章中,我们将带你踏上一场Spring Bean的时空之旅,深入了解每个作用域的特性和适用场景。

单例作用域

在Spring中,单例作用域(Singleton Scope)是默认的Bean作用域之一。当一个Bean被定义为单例时,Spring容器会在整个应用中维护该Bean的单一实例。每次请求该Bean时,都会返回相同的实例。这有助于节省资源,尤其是对于那些昂贵或频繁使用的对象。

如何声明单例Bean:

  1. 使用XML配置:
<bean id="mySingletonBean" class="com.example.MySingletonBean" scope="singleton"><!-- 其他配置属性 -->
</bean>
  1. 使用Java配置:
@Configuration
public class AppConfig {@Beanpublic MySingletonBean mySingletonBean() {return new MySingletonBean();}
}

在上述配置中,scope="singleton" 或者通过Java配置中的@Bean注解,没有指定@Scope注解,默认就是单例作用域。

特点:

  1. 唯一实例: Spring容器中只会创建该Bean的一个实例,不论有多少次请求该Bean。

  2. 全局共享: 适用于那些可以在整个应用中共享的对象。

  3. 节省资源: 对于那些占用大量资源或创建耗时的对象,使用单例可以减少资源消耗。

需要注意的是,虽然单例Bean在大多数情况下是很有用的,但也要小心可能引发的线程安全问题,因为单例Bean是在整个应用中共享的。确保单例Bean的状态是线程安全的,或者采用适当的同步机制。

原型作用域

在Spring中,原型作用域(Prototype Scope)是一种Bean的作用域,它与单例作用域相反。当一个Bean被定义为原型时,每次从容器中获取Bean时,都会创建一个新的实例。这确保每个请求得到的是一个独立的、新的Bean对象。

如何声明原型Bean:

  1. 使用XML配置:
<bean id="myPrototypeBean" class="com.example.MyPrototypeBean" scope="prototype"><!-- 其他配置属性 -->
</bean>
  1. 使用Java配置:
@Configuration
public class AppConfig {@Bean@Scope("prototype")public MyPrototypeBean myPrototypeBean() {return new MyPrototypeBean();}
}

在上述配置中,scope="prototype" 或者通过Java配置中的@Scope("prototype") 注解都将Bean声明为原型作用域。

特点:

  1. 每次请求新实例: 每次从容器中获取Bean时都会创建一个新的实例。

  2. 适用于状态不可共享: 适用于那些Bean实例的状态不可共享,每个请求需要一个独立的实例的情况。

  3. 资源消耗较大: 适用于那些占用较多资源、创建较慢的对象。

需要注意的是,由于原型Bean的每次请求都会创建一个新实例,容器不会管理这些实例的生命周期。这意味着,如果原型Bean中有需要在销毁时执行的逻辑(例如关闭资源),你需要自行管理。

会话作用域

在Spring中,会话作用域(Session Scope)是一种特殊的作用域,适用于Web应用程序中。当一个Bean被定义为会话作用域时,Spring容器会为每个用户会话(HTTP会话)创建一个独立的实例。这样可以确保在同一会话中共享的Bean实例,而不同会话之间的实例是独立的。

如何声明会话作用域Bean:

  1. 使用XML配置:
<bean id="mySessionBean" class="com.example.MySessionBean" scope="session"><!-- 其他配置属性 -->
</bean>
  1. 使用Java配置:
@Configuration
public class AppConfig {@Bean@Scope("session")public MySessionBean mySessionBean() {return new MySessionBean();}
}

在上述配置中,scope="session" 或者通过Java配置中的 @Scope("session") 注解都将Bean声明为会话作用域。

特点:

  1. 每个会话创建一个实例: 对于Web应用中的每个用户会话,Spring容器会创建一个独立的实例。

  2. 适用于会话状态跟踪: 适用于那些需要跟踪用户会话状态的Bean,例如用户登录信息等。

  3. 与HTTP会话关联: 与HTTP会话的生命周期相对应,当用户会话结束时,与之关联的Bean实例也被销毁。

会话作用域的使用通常限定在Web应用中,因为它依赖于HTTP会话的存在。这种作用域是有状态的,因此在设计时需要注意确保Bean的状态在会话之间不会产生冲突。

请求作用域

在Spring中,请求作用域(Request Scope)是一种特殊的作用域,适用于Web应用程序中。当一个Bean被定义为请求作用域时,Spring容器会为每个HTTP请求创建一个独立的实例。这样可以确保在同一HTTP请求中共享的Bean实例,而不同请求之间的实例是独立的。

如何声明请求作用域Bean:

  1. 使用XML配置:
<bean id="myRequestBean" class="com.example.MyRequestBean" scope="request"><!-- 其他配置属性 -->
</bean>
  1. 使用Java配置:
@Configuration
public class AppConfig {@Bean@Scope("request")public MyRequestBean myRequestBean() {return new MyRequestBean();}
}

在上述配置中,scope="request" 或者通过Java配置中的 @Scope("request") 注解都将Bean声明为请求作用域。

特点:

  1. 每个HTTP请求创建一个实例: 对于Web应用中的每个HTTP请求,Spring容器会创建一个独立的实例。

  2. 适用于与单个请求相关的Bean: 适用于那些需要与单个HTTP请求相关的Bean,例如处理用户请求的控制器。

  3. 与HTTP请求关联: 与HTTP请求的生命周期相对应,当HTTP请求结束时,与之关联的Bean实例也被销毁。

请求作用域的使用通常限定在Web应用中,因为它依赖于HTTP请求的存在。这种作用域是有状态的,因此在设计时需要注意确保Bean的状态在请求之间不会产生冲突。

自定义作用域

在Spring中,你可以通过实现Scope接口来创建自定义的作用域。自定义作用域可以满足特定需求,而不局限于Spring提供的默认作用域(如单例、原型、请求、会话等)。

以下是一个简单的示例,展示如何实现自定义作用域:

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;import java.util.HashMap;
import java.util.Map;public class CustomScope implements Scope {private final Map<String, Object> scopedObjects = new HashMap<>();private final Map<String, Runnable> destructionCallbacks = new HashMap<>();@Overridepublic Object get(String name, ObjectFactory<?> objectFactory) {if (!scopedObjects.containsKey(name)) {scopedObjects.put(name, objectFactory.getObject());// Register a destruction callbackdestructionCallbacks.put(name, () -> {// Your custom destruction logic hereSystem.out.println("CustomScope: Destroying bean with name " + name);});}return scopedObjects.get(name);}@Overridepublic Object remove(String name) {destructionCallbacks.remove(name);return scopedObjects.remove(name);}@Overridepublic void registerDestructionCallback(String name, Runnable callback) {destructionCallbacks.put(name, callback);}@Overridepublic Object resolveContextualObject(String key) {// Not used in this examplereturn null;}@Overridepublic String getConversationId() {// Not used in this examplereturn null;}
}

在这个例子中,CustomScope实现了Scope接口,并提供了自定义的作用域逻辑。其中:

  • get: 获取指定名称的Bean实例,如果不存在,则创建一个新实例。
  • remove: 移除指定名称的Bean实例。
  • registerDestructionCallback: 注册销毁回调,当作用域结束时,Spring容器会调用这些回调以执行自定义的销毁逻辑。
  • resolveContextualObject: 用于解析上下文对象,通常不使用。
  • getConversationId: 用于获取对话标识,通常不使用。

接下来,你需要将自定义作用域注册到Spring容器中。这可以通过配置文件或Java配置类完成:

@Configuration
public class AppConfig {@Beanpublic static CustomScope customScope() {return new CustomScope();}@Bean@Scope(value = "customScope", proxyMode = ScopedProxyMode.TARGET_CLASS)public MyCustomScopedBean myCustomScopedBean() {return new MyCustomScopedBean();}
}

在上述配置中,@Scope注解的value属性指定了使用的作用域,这里是customScope,而proxyMode属性设置为ScopedProxyMode.TARGET_CLASS,用于解决自定义作用域中的依赖注入问题。

请注意,这只是一个简单的自定义作用域示例,实际上可以根据具体需求实现更复杂的逻辑。

作用域的生命周期

在Spring中,不同作用域的Bean生命周期有着显著的差异。主要的作用域包括单例作用域(Singleton Scope)和原型作用域(Prototype Scope)。

单例作用域:

  1. 初始化: 单例Bean在容器启动时被创建(懒加载除外),并在整个应用程序的生命周期内保持不变。在首次请求该Bean时,Spring容器会调用构造函数、属性注入、初始化方法(如afterPropertiesSet@PostConstruct注解的方法)。

  2. 销毁: 单例Bean的销毁是在Spring容器关闭时进行的。当容器关闭时,Spring会调用单例Bean的销毁方法(如destroy@PreDestroy注解的方法)。

原型作用域:

  1. 初始化: 原型Bean在每次请求时都会创建一个新实例。每次请求该Bean时,Spring容器会调用构造函数、属性注入、初始化方法(如afterPropertiesSet@PostConstruct注解的方法)。

  2. 销毁: 原型Bean的销毁是由客户端代码负责的。Spring容器不会追踪原型Bean实例的生命周期,也不会在实例不再被引用时自动销毁。如果你的原型Bean实现了DisposableBean接口或使用了@PreDestroy注解的销毁方法,你需要手动调用这些方法。

影响:

  1. 资源消耗: 单例Bean由Spring容器管理,因此在整个应用程序生命周期内保持不变。这可能导致资源消耗较大。相反,原型Bean的资源消耗较小,因为每次请求都创建一个新实例。

  2. 状态共享: 单例Bean适用于需要在整个应用程序共享状态的情况,而原型Bean适用于需要保持独立状态的情况。

  3. 销毁控制: 单例Bean由Spring容器负责销毁,而原型Bean的销毁由客户端代码负责。

总的来说,选择单例作用域还是原型作用域取决于应用程序的具体需求。单例适用于共享状态的场景,而原型适用于每次请求都需要一个独立实例的场景。

实际应用场景

不同的作用域适用于不同的应用场景,以下是各个作用域的一些实际应用场景:

1. 单例作用域(Singleton Scope):

  • 共享状态的服务: 适用于需要在整个应用程序中共享状态的服务,例如配置管理服务、缓存服务等。

  • 工具类: 适用于那些无状态、只提供工具方法的类,因为这样的类在整个应用程序中可以被共享。

  • 线程安全的服务: 如果一个服务是线程安全的,并且需要在整个应用程序中被共享,那么可以考虑使用单例作用域。

2. 原型作用域(Prototype Scope):

  • 每次请求都需要一个新实例: 适用于那些在每次请求时都需要创建一个全新实例的Bean,例如Web应用中的表单处理器、控制器等。

  • 状态不可共享的Bean: 如果Bean的状态是不可共享的,且需要在每次请求中保持独立,可以考虑使用原型作用域。

  • 资源消耗较大的Bean: 对于创建耗时或占用大量资源的Bean,使用原型作用域可以避免在整个应用程序生命周期内占用过多资源。

3. 会话作用域(Session Scope):

  • 用户会话相关的Bean: 适用于需要在用户会话级别上共享状态的Bean,例如用户登录信息、购物车信息等。

  • 用户个性化设置: 如果有需要在用户会话级别上保存个性化设置的Bean,可以考虑使用会话作用域。

4. 请求作用域(Request Scope):

  • 每个HTTP请求需要一个新实例: 适用于那些与单个HTTP请求相关的Bean,例如处理用户请求的控制器、拦截器等。

  • 请求级别的数据: 如果有需要在请求级别上保存数据的Bean,可以考虑使用请求作用域。

  • 与请求相关的资源管理: 对于一些需要在请求结束时释放的资源,可以使用请求作用域,确保资源在请求完成后得到正确释放。

选择作用域时,需要根据具体的业务需求和Bean的性质来决定。合理使用不同的作用域有助于提高应用程序的性能和资源利用率。

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

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

相关文章

【KingbaseES】实现MySql函数Space

CREATE OR REPLACE FUNCTION SPACE(input_length integer) RETURNS text AS $$ BEGIN RETURN REPEAT( , input_length) AS SPACES; END; $$ LANGUAGE plpgsql;

深度学习课程实验二深层神经网络搭建及优化

一、 实验目的 1、学会训练和搭建深层神经网络&#xff1b; 2、掌握超参数调试正则化及优化。 二、 实验步骤 初始化 1、导入所需要的库 2、搭建神经网络模型 3、零初始化 4、随机初始化 5、He初始化 6、总结三种不同类型的初始化 正则化 1、导入所需要的库 2、使用非正则化…

实验笔记之——基于Linux服务器复现Instant-NGP及常用的tmux指令

之前博客实现了基于windows来复现Instant-NGP&#xff0c;本博文在linux服务器上测试 实验笔记之——基于windows复现Instant-NGP-CSDN博客文章浏览阅读444次&#xff0c;点赞15次&#xff0c;收藏7次。之前博客对NeRF-SLAM进行了调研&#xff0c;本博文先复现一下Intant-NGP。…

C++基础语法——基本知识、数据类型、运算符及程序流程结构

本专栏记录C学习过程包括C基础以及数据结构和算法&#xff0c;其中第一部分计划时间一个月&#xff0c;主要跟着黑马视频教程&#xff0c;学习路线如下&#xff0c;不定时更新&#xff0c;欢迎关注。 当前章节处于&#xff1a; >第1阶段-C基础入门 ---------第2阶段实战-通讯…

Java基础进阶(学习笔记)

注&#xff1a;本篇的代码和PPT图片来源于黑马程序员&#xff0c;本篇仅为学习笔记 static static 是静态的意思&#xff0c;可以修饰成员变量&#xff0c;也可以修饰成员方法 修饰成员的特点&#xff1a; 被其修饰的成员, 被该类的所有对象所共享 多了一种调用方式, 可以通过…

OpenHarmony源码转换器—多线程特性转换

本文讨论了如何将多线程的 Java 代码转换为 OpenHarmony ArkTS 代码​ 一、简介 Java 内存共享模型 以下示例伪代码和示意图展示了如何使用内存共享模型解决生产者消费者问题。 生产者消费者与共享内存间交互示意图 为了避免不同生产者或消费者同时访问一块共享内存的容器时…

数字信号处理期末复习——计算大题(一)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;V…

drf知识--11

补充 # 研究simple-jwt提供的Token类&#xff1a; 1、RefreshToken:生成refresh token的类 2、AccessToken:生成refresh token的类 3、Token&#xff1a;他们俩的父类 4、str(RefreshToken的对象)---得到字符串 refresh token&#xff0c;Token类写了 …

IO作业4.0

思维导图 创建出三个进程完成两个文件之间拷贝工作&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程回收子进程的资源 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <myhead.h> int …

win2003搭建DNS服务器域名解析方法

可以搭建DNS服务器的系统有很多&#xff0c;这里以win2003举例。 要在Windows 2003上搭建DNS服务器&#xff0c;需要按照以下步骤操作&#xff1a; 一 配置DNS服务器 1、打开“控制面板”,选择“添加/删除程序”,点击“添加/删除Windows组件”。 2、在“Windows组件向导”中…

批量AI智剪方法:轻松学会视频剪辑,让你的视频更精彩

在数字媒体时代&#xff0c;视频剪辑已经成为一项重要的技能。对于许多初学者来说&#xff0c;视频剪辑可能是一项复杂且耗时的任务。那么如何解决这个问题呢&#xff1f;现在一起来看看云炫AI智剪如何批量剪辑的方法&#xff0c;轻松完成视频剪辑工作&#xff0c;让视频更加精…

通往人工智能的 Go 之路

Agency 该库旨在为那些希望通过清晰、高效且符合 Go 语言惯例的方法来探索大型语言模型&#xff08;LLMs&#xff09;和其他生成式人工智能的开发人员而设计。 特点 纯 Go 语言&#xff1a;快速、轻量级&#xff0c;静态类型&#xff0c;无需涉及 Python 或 JavaScript编写清晰…

【科研指南8】如何快速批量下载一篇论文后的所有的参考文献?附赠Endnote分组论文管理

如何快速下载一篇论文后的所有的参考文献&#xff1f; 写在最前面第一步&#xff1a;在文献检索网站导出引用文献的RIS文件第二步&#xff1a;EndNote导入RIS文件&#xff0c;然后批量下载第三步&#xff08;可选&#xff09;&#xff1a;将之前找到的论文合并到Endnote一个数据…

node常见概念

node常见概念 非阻塞&异步 node的用处 模块化 文件是互不干扰的 文件之间能相互调用 只有函数才会产生作用域。 join和resolve的区别&#xff1a; join&#xff1a;拼接 resolve&#xff1a;解析 require是同步的 把文件读成一个字符串&#xff0c;包装成一个自执行函数&am…

FLatten Transformer:聚焦式线性注意力模块

线性注意力将Softmax解耦为两个独立的函数&#xff0c;从而能够将注意力的计算顺序从(querykey)value调整为query(keyvalue)&#xff0c;使得总体的计算复杂度降低为线性。然而&#xff0c;目前的线性注意力方法要么性能明显不如Softmax注意力&#xff0c;并且可能涉及映射函数…

分享10篇优秀论文,涉及图神经网络、大模型优化、表格分析

引言 第38届AAAI人工智能年度会议将于2024年2月在加拿大温哥华举行。今天给大家分享十篇AAAI2024论文&#xff0c;主要涉及图神经网络&#xff0c;大模型幻觉、中文书法文字生成、表格数据分析、KGs错误检测、多模态Prompt、思维图生成等。 论文获取方式&#xff0c;回复&am…

高效分割视频:批量剪辑,轻松提取m3u8视频技巧

在数字媒体时代&#xff0c;视频分割是一项常见的需求。无论是为了编辑、分享还是其他要求&#xff0c;经常要将长视频分割成多个短片。传统的视频分割方法往往需要手动操作&#xff0c;既耗时又容易出错。现在来看云炫AI智剪高效分割视频的方法&#xff0c;批量剪辑并轻松提取…

LRU的设计与实现(算法村第五关黄金挑战)

146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存…

【RF 计算公式】计算自由空间损耗

1、 电信链路的基本公式 自由空间传播可使用两种不同的方法计算&#xff0c;每种方法均适用于一种特定类型的业务。 1. 1 点到区链路 如果发射机服务于若干随机分布的接收机&#xff08;广播、移动业务&#xff09;&#xff0c;则电场强的计算应在与发射机有适当距离的位置进…

手机流量卡推广分销网站php源码,多功能的号卡推广分销管理系统

源码简介 拥有多个接口&#xff0c;包括运营商接口&#xff0c;并支持无限三级代理。 最简单易用的PHP系统&#xff0c;它自带自动安装向导&#xff0c;可以让你轻松安装和部署。 该系统集成了多个第三方接口资源&#xff0c;能够满足你的不同需求。采用全系统双色主题&…