Spring - Bean的6种作用域

news/2024/6/17 13:41:23 标签: java, 开发语言

  • 1、Bean作用域问题
    • 2、作用域定义
    • 2.1、Bean的6种作用域
      • singleton 单例模式
      • prototype 原型作用域
      • request 请求作用域
      • session 会话作用域
      • application 全局作用域(了解)
      • websocket
    • 单例作用域 vs 全局作用域
  • 2.设置作用域

1、Bean作用域问题

通过一个案例来看Bean的作用域。假设有一个公共的Bean对象,提供给A类和B类使用,然而在A类使用的过程中,修改了Bean的数据,导致B类在使用Bean的时候产生了预期之外的逻辑错误。

预期结果是公共Bean可以在各自类中被修改,但不能影响其他类使用(使用时还是Bean的初始数据)。

公共Bean:

java">@Component
public class Users {
    @Bean
    public User user1(){
        User user = new User();
        user.setName("zhangsan");//注意 初始化为 zhangsan
        user.setId(1);
        return user;
    }
}

User对象:

java">public class User {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

A类使用时,修改了数据:把name修改成了Lisi

java">@Controller
public class AController {
    @Autowired
    private User user;
    public User getUser1(){
        System.out.println("Bean 原 name :"+user.getName());
        user.setName("Lisi");//A类修改了Bean原生数据
        return user;
    }
}

B类再去使用公共Bean时:

java">@Controller
public class BController {
    @Autowired
    private User user1;

    public User getUser1(){
        User user = user1;
        return user;
    }
}

打印A和B类使用公共Bean 的值:

java">public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.config.xml");
        
        AController aController = context.getBean(AController.class);
        System.out.println("A类修改后 name :"+aController.getUser1().toString());
        
        BController bController = context.getBean(BController.class);
        System.out.println("B读取到的 name :"+bController.getUser1().toString());
    }
}

运行结果:

在这里插入图片描述

原因分析:

以上运行结果的原因是:因为Bean默认情况下是单例模式(singleton),也就是所有人使用的都是同一个Bean对象。因为使用单例模式可以很大程度上提高性能,所以在spring中Bean的作用域默认也是singleton单例模式。

2、作用域定义

程序中变量的可用范围就叫做作用域,或者说在源代码中定义某个变量在某个区域就叫做作用域。而Bean的作用域是指Bean在Spring整个框架中的某种行为模式,比如singleton单例作用域,就表示Bean在spring中只有一份,全局共享的,当A修改了这个值后,那么B再使用时就是修改后的值。

2.1、Bean的6种作用域

Spring容器在初始化一个Bean对象时,会指定该实例的作用域。spring有6种作用域,最后4种是基于Spring MVC生效的:

1.  singleton:单例模式
2.  prototype:原型作用域(多例作用域)
3.  request:请求作用域
4.  session:会话作用域
5.  application:全局作用域
6.  websocket:HTTP  WebSocket 作用域

注意后4种是SpringMVC中的值,在普通的Spring项目中只有前两种。

singleton 单例模式

  • 该作⽤域下的Bean在IoC容器中只存在⼀个实例:获取Bean(即通过 applicationContext.getBean等⽅法获取)及装配Bean(即通过@Autowired注⼊)都是同⼀个对象。
  • 场景:通常⽆状态的Bean使⽤该作⽤域。⽆状态表示Bean对象的属性状态不需要更新。
  • 备注:Spring默认选择该作⽤域。

prototype 原型作用域

  • 描述:每次对该作用域下的Bean的请求都会创建一个新的实例:获取Bean(即通过 applicationContext.getBean等⽅法获取)及装配Bean(即通过@Autowired注⼊)都是同新的对象。
  • 场景:通常有状态的Bean使用该作用域。

request 请求作用域

  • 描述:每次http请求会创建新的Bean实例,类似于prototype
  • 场景:⼀次http的请求和响应的共享Bean
  • ⼀次http的请求和响应的共享Bean

session 会话作用域

  • 描述:在⼀个http session中,定义⼀个Bean实例

  • 场景:⽤户回话的共享Bean, ⽐如:记录⼀个⽤户的登陆信息

    备。

  • 备注:限定SpringMVC中使⽤

application 全局作用域(了解)

  • 描述:在⼀个http servlet Context中,定义⼀个Bean实例。
  • 场景:Web应⽤的上下⽂信息,⽐如:记录⼀个应⽤的共享信息。
  • 备注:限定SpringMVC中使⽤。

websocket

  • 描述:在⼀个HTTP WebSocket的⽣命周期中,定义⼀个Bean实例。
  • 场景:WebSocket的每次会话中,保存了⼀个Map结构的头信息,将⽤来包裹客户端消息头。第⼀次初始化后,知道WebSocket结束都是同一个Bean。
  • 备注:限定Spring WebSocket中使⽤。

单例作用域 vs 全局作用域

  • singleton 是 Spring Core 的作⽤域;application 是 Spring Web 中的作⽤域;
  • singleton 作⽤于 IoC 的容器,⽽ application 作⽤于 Servlet 容器。

2.设置作用域

@Scope既可以修饰方法也可以修饰类

  1. 使用@Scope标签设置Bean的作用域: 设置为 prototype 全局作用域
java">@Component
public class Users {
    @Scope("prototype")//设置为 prototype 全局作用域
    @Bean
    public User user1(){
        User user = new User();
        user.setName("zhangsan");//注意 初始化为 zhangsan
        user.setId(1);
        return user;
    }
}

运行结果:此时A修改数据,不会影响B读取的数据。

在这里插入图片描述

  1. 使用枚举设置@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
java">@Component
public class Users {
    //@Scope("prototype")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public User user1(){
        User user = new User();
        user.setName("zhangsan");//注意 初始化为 zhangsan
        user.setId(1);
        return user;
    }
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TiFDyiP-1686991444637)(C:\Users\COFFEEWEN\AppData\Roaming\Typora\typora-user-images\image-20230616150256693.png)]


http://www.niftyadmin.cn/n/442692.html

相关文章

在 Quarkus 中的使用 Mutiny 进行响应式编程

在 Quarkus 中使用 Mutiny - 事件驱动的 Java 响应式编程库 本教程介绍在 Quarkus 中使用事件驱动的 Mutiny 响应式编程库 以应对异步系统开发中的挑战。 概述 Mutiny 是一个(Reactive Programming)响应式编程库, 事件是 Mutiny 的设计核心&#xff0…

python基础-函数专题

hello,这里是GUIDM 这一篇是python基础函数篇,希望这张内容对您能有所帮助。 函数-代码段。 功能单一 复用性 创建一个函数三要素: 1、函数名–命名规范:顾名思义、驼峰法(大驼峰【定义类名时】ClassName、小驼峰getName&#xff…

c++系列之string类的常用接口函数

💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 string string时表示字符串的字符类 //使用 string类包含#include 头文件 以及…

4.pixi.js编写的塔防游戏(类似保卫萝卜)-a星寻路

游戏说明 一个用pixi.js编写的h5塔防游戏,可以用electron打包为exe,支持移动端,也可以用webview控件打包为app在移动端使用 环境说明 cnpm6.2.0 npm6.14.13 node12.22.7 npminstall3.28.0 yarn1.22.10 npm config list electron_mirr…

如何翻译 Markdown 文件?-2-几种商业及开源解决方案介绍

背景 近期在搭建英文博客-<e-whisper.com>, 需要对现有的所有中文 Markdown 翻译为英文。 需求如下&#xff1a; 将 Markdown 文件从中文 (zh-CN) 翻译为英文 (en)翻译后要保留 Markdown 的完整格式部分 Markdown block 不需要翻译&#xff0c;如&#xff1a;front-ma…

mysql 集群 MGR

mysql安装&#xff08;3台服务&#xff09; 1下载 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.11-linux-glibc2.12-x86_64.tar.gz 2解压mysql wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.11-linux-glibc2.12-x86_64.tar.gz tar -zxvf…

操作系统2:进程的描述与控制

目录 1、什么是前驱图&#xff1f; 2、进程的定义和描述 &#xff08;1&#xff09;什么是进程&#xff1f; &#xff08;2&#xff09;进程的基本状态及转换 &#xff08;3&#xff09;挂起操作和进程状态的转换 3、进程管理中的数据结构 &#xff08;1&#xff09;进程…

define 和 typedef 两者的联系和区别

define用来定义一些常量和宏函数&#xff0c;然后在预处理阶段&#xff0c;编译器会直接替换 typedef用于定义一些新的类型&#xff0c;看起来更加直观或写起来更加方便 比如在单片机中&#xff0c;我们经常使用unsigned char 但是经常写又太麻烦&#xff0c;就会使用: &am…