2023.11.11 关于 Spring 中 Bean 的作用域

news2025/1/13 6:00:31

目录

Bean 的作用域

作用域的定义

Singleton(单例作用域)

Prototype(原型作用域)

Request(请求作用域)

Session(会话请求)

Application(全局作用域)

WebSocket(WebSocket 会话作用域 )

设置 Bean 的作用域

@Scope 注解

使用方式建议


Bean 的作用域

作用域的定义

  • 作用域(Scope)指变量、函数或对象在程序中可见和访问的范围
  • Bean 的作用域 指 Bean 在 Spring 整个框架中的某种 行为模式

Bean 的 6 种作用域

  • Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域

Singleton(单例作用域)

  • 该作用域下的 Bean 在 Spring 容器中只存在一个实例:获取 Bean(即通过 context.getBean 等方法获取)及装配 Bean(通过 @Autowired 注入)都是同一个对象
  • Spring 容器在第一次请求时创建该实例,并在后续请求中返回相同的实例
  • 默认情况下,Spring 的 Bean 作用域为 Singleton
  • 因为 单例模式 的性能更好

Prototype(原型作用域)

  • 可理解为 多例作用域

  • 每次请求获取 Bean 时,都会创建一个新的实例

  • 每次获取 Bean 时都会返回一个新的对象,即原型作用域的 Bean 实例不会被共享

Request(请求作用域)

  • 在 Web 应用程序中,每个 HTTP 请求将创建一个新的 Bean 实例,并且该实例仅在当前请求的范围内可见
  • 对于每个请求,都会有一个单独的 Bean 实例

Session(会话请求)

  • 在 Web 应用程序中,每个用户会话均会创建一个新的 Bean 实例,并且该实例仅在当前用户会话的范围内可见
  • 对于每个用户会话,都会有一个单独的 Bean 实例

Application(全局作用域)

  • 在 Web 应用程序中,整个应用程序范围内只会创建一个Bean 实例,并且该实例将被共享和重用

WebSocket(WebSocket 会话作用域 )

  • 在基于 WebSocket 的应用程序中,每个 WebSocket 会话均会创建一个新的 Bean 实例,并且该实例仅在当前 WebSocket 会话的范围内可见

注意:

  • 在普通的 Spring 项目中只有前两种作用域,即前两种为 Spring 核心作用域
  • 后四种状态是 Spring MVC 中的作用域

建议阅读下文之前 点击下方链接了解 Lombok 的作用

Lombok 的作用和使用


实例理解

  • 我们先创建一个实体类 User
import lombok.Data;

@Data
public class User {
    public int id;
    public String name;
}
  • 再创建一个 UserBean 类,用来向 Spring 容器中 存储 User 类型的 Bean 对象
  • 此处向 Spring 容器中存入一个 id 为 user,且 name = 张三的 Bean 对象
import com.java.demo.enity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class UserBeans {
    @Bean
    public User user() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}
  • 新创建 UserController 类
  • 该类中新创建了一个 myUser 对象,且该对象赋值于注入进来的 user Bean 对象
  • 并修改 myUser 对象的 name 属性
  • 将从 user Bean 对象赋值而来的 name = 张三,修改为 name = 小林
import com.java.demo.enity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {

    @Autowired
    private User user;

    public void printUser() {
        System.out.println("UserController 类注入的 user Bean 对象,也就是 user 变量的初始值 -> " + user.toString());
//        修改 User
        User myUser = user;
        myUser.setName("小林");
        System.out.println("UserController 类中的 myUser 对象 -> " + myUser.toString());
        System.out.println("UserController 类修改 myUser 对象 name 属性后再次打印 user 变量 -> " + user.toString());
    }
}
  • 新创建 UserController2 类
  • 同样在该类中注入 user Bean 对象
import com.java.demo.enity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController2 {

    @Autowired
    private User user;

    public void printUser2() {
        System.out.println("UserController2 类注入的 user Bean 对象 -> " + user.toString());
    }
}
  • 最后再创建一个启动类
  • 该类用来从 Spring 容器中拿 UserController 类和 UserController2 类的 Bean 对象,并调用它们的成员方法
import com.java.demo.controller.UserController;
import com.java.demo.controller.UserController2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");

        UserController userController = context.getBean("userController",UserController.class);
        userController.printUser();

        UserController2 userController2 = context.getBean("userController2",UserController2.class);
        userController2.printUser2();
    }
}

运行结果:

  • 该运行结果与我们的预期结果不同诶!
  • 为啥 UserController2 类中从 Spring 容器中拿到的 user Bean 对象其 name = 小林 ?

原因解释:

  • 正因为默认情况下,Spring 的 Bean 作用域为 Singleton,即 单例作用域
  • 即存储在 Spring 容器中的 id = user 的 Bean 对象仅有一份
  • 所以此处的 user 变量和 myUser 变量 均指向同一个对象(引用)
  • 即 myUser 变量在对其 name 进行修改时
  • 其他任何注入了 id = user 的 Bean 对象 的变量,也会跟着修改 name

设置 Bean 的作用域

@Scope 注解

  • 我们可以通过 @Scope 注解来设置 Bean 对象的作用域

实例理解

  • 如果我们不主动设置该 Bean 对象的作用域,其默认为 Singleton(单例作用域)
  • 所以为了解决上述实例问题所产生的问题,我们可以将该 Bean 对象主动设置为 prototype(原型作用域),即多例模式

方式一:直接在 @Scope 注解中填入 prototype

import com.java.demo.enity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
public class UserBeans {
    @Bean
    @Scope("prototype")
    public User user() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

方式二:使用 ConfigurableBeanFactory 接口中定义的常量 SCOPE_PROTOTYPE,该常量表示原型作用域

import com.java.demo.enity.User;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
public class UserBeans {
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User user() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}
  • 当我们修改完 Bean 对象的作用域时,再次运行启动类,观察运行结果

运行结果:

  •  UserController2 类中从 Spring 容器中拿到的 user Bean 对象其 name = 张三
  • 也就是说,在 UserController 类中,进行的修改操作并未影响到 Spring 容器中的初始 Bean 对象

使用方式建议

  • 上述两种方式起到的效果是相同的,但是推荐使用第二种方式
  • 使用第一种 直接填入 prototype 方式的前提是 你能够清楚的记得该单词是如何拼写的
  • 而第二种方式,IDEA 自带自动补全提示,可以保证我们不出错!

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

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

相关文章

计算机毕业设计 基于Springboot的影院购票管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

立冬特辑-----链表OJ题优选合集~~

目录 ​​​​​​​前言🌳 1.链表中倒数第k个结点🌸 1.1 思路 1.2 代码 2. 链表的回文结构🪸 2.1 思路 2.2 代码 3.相交链表🌪️ 3.1 思路 3.2 代码 4.环形链表I🌊🛳️ 4.1 思路 4.2 代码 4…

大数据治理——为业务提供持续的、可度量的价值(二)

第二部分:元数据集成体系结构 在明确了元数据管理策略后需要确定实现该管理策略所需的技术体系结构,即元数据集成体系结构。元数据集成体系结构涉及到多个概念,如元模型、元-元模型、公共仓库元模型(CWM)等&#xff0…

人工智能时代,掌握未来技术趋势,成为领先者

人工智能时代,掌握未来技术趋势,成为领先者 摘要:本文将从热门技术趋势、技术应用场景、技术实践案例、技术发展趋势等角度进行探讨,帮助读者更好地了解技术前沿动态,为自身职业发展提供指导。在人工智能时代&#xf…

作业提交产品的爽点、痛点和痒点分析以及开源软件介绍

目录 1 爽点1.1 什么是爽点1.2 如何构成爽点1.3 案例 2 痛点2.1 什么是痛点2.2 如何构成痛点2.3 案例分析 3 痒点3.1 什么是痒点3.2 如何构成痒点3.3 案例分析 4 开源软件Canvas LMS4.1 链接地址4.2 简介4.3 特点和功能4.4 功能展示图片 1 爽点 1.1 什么是爽点 即时满足&#…

阿里云-maven私服idea访问私服与组件上传

1.进入aliyun制品仓库 2. 点击 生产库-release进入 根据以上步骤修改本地 m2/setting.xml文件 3.pom.xml文件 点击设置获取url 4. idea发布组件

C语言--每日五道选择题--Day8

第一题 1、下列程序的输出是&#xff08; &#xff09; #include<stdio.h> int main() {int a[12] {1,2,3,4,5,6,7,8,9,10,11,12};int *p[4];int i;for(i0;i<4;i){p[i]&a[i*3];}printf("%d\n"&#xff0c;p[3][2]);return 0; } A: 上述程序有错误 B: 6…

在Win11中使用docker安装Oracle19c

在Win11中使用docker安装Oracle19c 首先是去docker官网下 docker for windows安装oracle19c首先下载image运行镜像在工具中登录可能遇到的问题 首先是去docker官网下 docker for windows 官网&#xff1a; https://www.docker.com/get-started/ 如果Windows是专业版&#xff0…

[100天算法】-面试题 04.01.节点间通路(day 72)

题目描述 节点间通路。给定有向图&#xff0c;设计一个算法&#xff0c;找出两个节点之间是否存在一条路径。示例1:输入&#xff1a;n 3, graph [[0, 1], [0, 2], [1, 2], [1, 2]], start 0, target 2 输出&#xff1a;true 示例2:输入&#xff1a;n 5, graph [[0, 1], …

微信的聊天记录导出到网页中的最快方法,语音能听,图片视频能看

12-7 如果你有把微信的聊天记录导出到表格或者网页上的需求&#xff0c;适合看看本文章&#xff0c;本文的方法可以让你把微信的聊天记录导出备份&#xff0c;可以在完全脱离微信的情况下随时调取查看聊天数据。 本文介绍的软件可以导出两种格式的聊天记录备份文件&#xff0…

C/C++数字判断 2021年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C数字判断 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C数字判断 2021年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入一个字符&#xff0c;如何输入的字符是数字&#x…

在线生成二维码--支持彩色二维码和包含Logo

具体请前往&#xff1a;在线二维码生成工具--可将网址等内容生成为指定大小&#xff0c;指定颜色的彩色二维码,同时支持添加Logo

win环境Jenkins高级配置各种插件和启动jar包

今天分享Jenkins高级配置各种插件&#xff0c;在看此篇之前必须先了解上一篇博客内容&#xff0c;因为此篇是在上篇的基础上完善的&#xff1a; 一、git仓库的多分支选择 想要多分支选择部署&#xff0c;需要全局安装Git parameter 插件 1、点击入口 来到 2、点击进入 安装一…

第24章_mysql性能分析工具的使用

文章目录 1. 数据库服务器的优化步骤2.查看系统性能参数3. 统计SQL的查询成本&#xff1a;last_query_cost4. 定位执行慢的 SQL&#xff1a;慢查询日志4.1 开启慢查询日志参数4.2 查看慢查询数目4.3 测试慢sql语句&#xff0c;查看慢日志4.4 系统变量 log_output&#xff0c; l…

Day03:注意事项、this关键字、构造器、JavaBean、String、ArrayList

OOP的注意事项 类名要跟class文件名一致&#xff08;一个class可以有多个类&#xff0c;但只有一个public&#xff0c;且与文件名一致&#xff09;&#xff0c;命名介意大驼峰&#xff1b;如果某个对象没有变量指向他&#xff0c;就成垃圾对象了&#xff08;空指针&#xff09…

【网络奇遇记】你真的了解网络中的电路交换、分组交换和报文交换吗?

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. 电路交换1.1 电路交换讲解1.2 电路交换实例 二. 分组交换1.1 分组交换讲解1.2 分组交换实例1.3 …

深度学习之基于Django+Tensorflow商品识别管理系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 项目简介 本系统是一个基于DjangoTensorflow的商品识别管理系统。通过深度学习技术&#xff0c;实现商品的自动识别…

S7-1200PLC和SMART PLC开放式以太网通信(UDP双向通信)

S7-1200PLC的以太网通信UDP通信相关介绍还可以参考下面文章链接: 博途PLC开放式以太网通信TRCV_C指令应用编程(运动传感器UDP通信)-CSDN博客文章浏览阅读2.8k次。博途PLC开放式以太网通信TSENG_C指令应用,请参看下面的文章链接:博途PLC 1200/1500PLC开放式以太网通信TSEND_…

【LeetCode】挑战100天 Day10(热题+面试经典150题)

【LeetCode】挑战100天 Day10&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-122.1 题目2.2 题解 三、面试经典 150 题-123.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

Leetcode刷题详解——优美的排列

1. 题目链接&#xff1a;526. 优美的排列 2. 题目描述&#xff1a; 假设有从 1 到 n 的 n 个整数。用这些整数构造一个数组 perm&#xff08;下标从 1 开始&#xff09;&#xff0c;只要满足下述条件 之一 &#xff0c;该数组就是一个 优美的排列 &#xff1a; perm[i] 能够被…