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

2023.11.11 关于 Spring 中 Bean 的作用域

目录

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 {@Beanpublic 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 {@Autowiredprivate User user;public void printUser() {System.out.println("UserController 类注入的 user Bean 对象,也就是 user 变量的初始值 -> " + user.toString());
//        修改 UserUser 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 {@Autowiredprivate 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.lryc.cn/news/226653.html

相关文章:

  • 5 Paimon数据湖之表数据查询详解
  • 时间序列预测实战(十二)DLinear模型实现滚动长期预测并可视化预测结果
  • 封神教程:腾讯云3年轻量应用服务器老用户购买方法
  • Ubuntu(WSL2) 安装最新版的 cmake
  • Android---内存泄漏的优化
  • C/S架构学习之基于UDP的本地通信(客户机)
  • 【性能测试】服务端中间件docker常用命令解析整理(详细)
  • 【探索Linux】—— 强大的命令行工具 P.14(进程间通信 | 匿名管道 | |进程池 | pipe() 函数 | mkfifo() 函数)
  • 图论12-无向带权图及实现
  • 每日一题(LeetCode)----数组--有序数组的平方
  • SpringCloud微服务:Eureka
  • 19.删除链表的倒数第N个结点(LeetCode)
  • PyTorch技术和深度学习——三、深度学习快速入门
  • 360导航恶意修改浏览器启动页!我的chrome和IE均中招,如何解决?
  • RabbitMQ的高级特性
  • Java自学第10课:JavaBean和servlet基础
  • AR打卡小程序:构建智能办公的新可能
  • Python环境安装、Pycharm开发工具安装(IDE)
  • 报时机器人的rasa shell执行流程分析
  • C#开发的OpenRA游戏之世界存在的属性UpdatesPlayerStatistics(2)
  • Ocelot:.NET开源API网关提供路由管理、服务发现、鉴权限流等功能
  • wsl [Ubuntu20.04.6] 安装 Hadoop
  • 2023华为ict网络赛道初赛(部分)试题
  • rabbitMq虚拟主机概念
  • 2-CentOS7.9下安装docker
  • 【已验证-直接用】微信小程序wx.request请求服务器json数据并渲染到页面
  • 如何提高小红书笔记的互动率
  • RabbitMQ 系列教程
  • 无感刷新token
  • 【Python大数据笔记_day06_Hive】