Bean 的六种作用域

news2024/12/25 14:03:01

观前提示:本篇博客演示使用的 IDEA 版本为2021.3.3版本,使用的是Java8(又名jdk1.8)

前端使用VSCode(Visual Studio Code1.78.2)

电脑使用的操作系统版本为 Windows 10


目录

前言

Bean

Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作⽤域。

1.  singleton:单例作用域

1.1 原因

2.  prototype:原型作用域(多例作用域)

2.1 设置作用域

3.  request:请求作用域

4.  session:回话作用域

5.  application:全局作用域

6. websocket:HTTP WebSocket 作⽤域


 前言

本篇博客将对 Spring 里面的 Bean 的六种作用域进行介绍,重点介绍单例模式与原型模式, 后面四种是 Spring MVC 中的值, 后面的博客再介绍

Bean

Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作⽤域。

1.  singleton:单例作用域

先来看一个栗子

先创建一个 com.java.demo.enity 的包 里面放一个 user 类, 类里面有 id 和 name, 使用 lombok 来处理 Get, Set 以及 ToString

package com.java.demo.enity;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class User {
    private int id;
    private String name;
}

再建立一个 com.java.demo.component 的包, 里面放 UserBeans, 对 User 里面的数据进行初始化

package com.java.demo.component;

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 类里面的 name 和 id
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

再建立一个 com.java.demo.controller 的包, 建立 userController 类, 在局部变量修改 Bean, 分别打印局部变量和全局变量,查看结果

package com.java.demo.controller;

import com.java.demo.enity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    //依赖注入,把 User 类型的 Bean 注入 UserController 属性中。
    @Autowired
    private User user;

    public void printUser() {
        // 先打印一次 user, 看看结果是什么
        System.out.println(user);

        //在局部变量里面对 Bean 进行修改
        User myUser = user;
        myUser.setName("李四");
        //查看局部变量修改后局部变量的打印结果
        System.out.println("myUser -> " + myUser);
        //查看局部变量修改后全局变量的打印结果
        System.out.println("user -> " + user);
    }
}

再建立一个 com.java.demo.controller 的包, 建立 userController2 类 , 专门打印 Bean

package com.java.demo.controller;

import com.java.demo.enity.User;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class UserController2 {
    @Resource
    private User user;

    public void printUser2() {
        // 专门打印看看能不能拿到 张三
        System.out.println("user -> " + user);
    }
}

在创建一个 App 类,用来进行启动

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 controller = context.getBean("userController", UserController.class);
        controller.printUser();
        UserController2 controller2 = context.getBean("userController2", UserController2.class);
        controller2.printUser2();
    }
}

上述代码总共进行了四次打印, 预估结果, 第一次打印:张三(全局变量), 第二次打印:李四(局部变量修改), 第三次打印:张三(局部变量修改不会影响全局变量)

第四次打印: 张三

但是结果真的是这样吗?

 

结果除了第一个符合预期, 后面的全部的不符合预期,这是为什么? 明明只是修改了局部变量,他却连全局变量都被修改了

1.1 原因

因为 Spring默认是 单例模式, 翻译就是整个 Spring 里面的 Bean 都是同一个对象, 因为 Bean 只有一份,修改一次之后(不论修改的是全局还是局部),都是永久修改

为什么他默认是单例模式呢? , 当然是为了提高性能, 他只需要初始化一次, 同样 JVM 的类加载也只需要执行一次


2.  prototype:原型作用域(多例作用域)

不想要单例模式可以进行修改, 例如修改成多例作用域

2.1 设置作用域

要在设置的时候就对他进行修改,不能获取到了再修改, 所以是在 UserBeans

两种写法

1. 直接设置值:@Scope("prototype")

package com.java.demo.component;

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 类里面的 name 和 id
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

 

2. 使⽤枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

package com.java.demo.component;

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 类里面的 name 和 id
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

 

更加推荐使用第二种写法, 因为第一个错了不容易发现,第二个错了 idea 会提示


3.  request:请求作用域

官⽅说明:Scopes a single bean definition to the lifecycle of a single HTTP request. That is,
each HTTP request has its own instance of a bean created off the back of a single bean
definition. Only valid in the context of a web-aware Spring ApplicationContext.
描述:每次http请求会创建新的Bean实例,类似于prototype
场景:⼀次http的请求和响应的共享Bean
备注:限定SpringMVC中使⽤


4.  session:回话作用域

官⽅说明:Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in
the context of a web-aware Spring ApplicationContext.
描述:在⼀个http session中,定义⼀个Bean实例
场景:⽤户回话的共享Bean, ⽐如:记录⼀个⽤户的登陆信息
备注:限定SpringMVC中使⽤


5.  application:全局作用域

官⽅说明:Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in
the context of a web-aware Spring ApplicationContext.
描述:在⼀个http servlet Context中,定义⼀个Bean实例
场景:Web应⽤的上下⽂信息,⽐如:记录⼀个应⽤的共享信息
备注:限定SpringMVC中使⽤


6. websocket:HTTP WebSocket 作⽤域

官⽅说明:Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the
context of a web-aware Spring ApplicationContext.
描述:在⼀个HTTP WebSocket的⽣命周期中,定义⼀个Bean实例
场景:WebSocket的每次会话中,保存了⼀个Map结构的头信息,将⽤来包裹客户端消息头。第⼀
次初始化后,直到WebSocket结束都是同⼀个Bean。
备注:限定Spring WebSocket中使⽤
 


本文完,感谢观看,不足之处请在评论区指出 !

 

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

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

相关文章

chatgpt赋能python:Python怎样能通过值找到键

Python怎样能通过值找到键 Python是一种高级编程语言,它在工业、医疗、科学、财务等多个行业中被广泛使用,是数据科学、人工智能和深度学习等领域的首选语言。在Python编程中,有时候我们需要在字典中根据值查询对应的键,本文将介…

chatgpt赋能python:Python排序算法大全

Python排序算法大全 导言 排序是程序员日常工作中最常见的操作之一。Python提供了许多实现排序算法的库和函数,本文将带您了解这些排序方法。 初级排序算法 冒泡排序 Bubble Sort 冒泡排序是一种简单的排序算法。它通过不断交换相邻的元素,将大的元…

【微服务架构设计和实现】4.2 服务边界的定义和划分

第一章:【云原生概念和技术】 第二章:【容器化应用程序设计和开发】 第三章:【基于容器的部署、管理和扩展】 第四章:【4.1 微服务架构概述和设计原则】 4.2 服务边界的定义和划分 4.2 服务边界的定义和划分4.2.1 什么是服务边…

docker创建Ubuntu,Ubuntu创建桌面环境,本机使用VNC连接

题目:docker创建Ubuntu,Ubuntu创建桌面环境,本机使用VNC连接 文章目录 前言docker创建基于Ubuntu:20.04的容器使用ssh连接容器容器安装桌面环境本机电脑使用VNC连接测试用python来创建的ui能否显示坑参考 前言 为什么我想要用ubuntu的桌面环…

RFID课程要点总结_2 Identification

2. Identification 简单说RFID就是物体上贴tag,用reader上的antenna去读取,这三个是主要组成。 Reader’s function Energy supply: 比如有的标签自身不带能量需要reader提供信号中蕴含的能量 Communication: 最基本的功能,和tag识别&…

Flink CDC、OGG、Debezium等基于日志开源CDC方案对比

先上一张图,后面再慢慢介绍: CDC概述 CDC 的全称是 Change Data Capture ,在广义的概念上,只要能捕获数据变更的技术,我们都可以称为 CDC 。我们目前通常描述的CDC 技术主要面向数据库的变更,是一种用于捕…

56、基于51单片机智能医院红外点滴检测输液器报警系统设计(程序+原理图+PCB源文件+参考论文+参考PPT+元器件清单等)

引 言 目前,国际上每年每人的静脉输液量平均为2.5-3.3瓶,就我国而言,每年每人平均输液量8瓶,总量超过100亿瓶,其中每年约有39万人死于输液不良反应 。在如今新冠肺炎疫情持续的情况下,静脉输液仍是临床医学…

chatgpt赋能python:Python中如何选取list13列

Python中如何选取list 1 3列 介绍 对于SEO优化来说,选取适当的数据是至关重要的一步。Python是一门强大的编程语言,可以帮助人们快速而准确地处理数据,进而选择最佳数据进行SEO。在Python中,我们可以使用一些简单的方法来选择li…

kubespray部署kubernetes集群

kubespray部署kubernetes集群 1、kubespray简介 Kubespray 是开源的部署生产级别 Kubernetes 集群的项目,它整合了 Ansible 作为部署的工具。 可以部署在 AWS,GCE,Azure,OpenStack,vSphere,Packet(Bare m…

马原否定之否定观点

事物普遍联系和发展 事物之间的普遍联系的 答案B C考察的是联系的条件性 1.联系对事物的发展有制约和支撑的作用 2.联系的条件可以相互转化 所以我们可以将不利条件转化成有利条件 3.建立联系必须尊重客观规律。 对立统一是事物发展的根本规律、 唯物辩证法揭示了事物发展一…

ELK日志收集系统集群实验

目录 一、实验拓扑 二、环境配置 (一)设置各个主机的IP地址为拓扑中的静态IP,在两个节点中修改主机名为node1和node2并设置hosts文件 1、在虚拟机node1上操作 2、在虚拟机node2上操作 3、测试node1与node2的通联性 三、 安装node1与node2节点的elasticsearch…

大数据Doris(四十四):kafka json 数组格式数据导入到Doris

文章目录 kafka json 数组格式数据导入到Doris 一、创建 Doris 表 二、创建 Kafka topic

[论文笔记]Bidirectional LSTM-CRF Models for Sequence Tagging

引言 本文是论文Bidirectional LSTM-CRF Models for Sequence Tagging的阅读笔记。这篇论文是15年发表的,比上次介绍的那篇还要早。 首次应用双向LSTM+CRF(BI-LSTM-CRF)到序列标注数据集。BI-LSTM-CRF模型可以有效地使用双向输入特征,也因为CRF层可以利用句子级标签信息。…

前端web入门-CSS-day06

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 一、标准流 二、Flex 布局 组成 主轴对齐方式 侧轴对齐方式 修改主轴方向 弹性伸缩比 弹性盒子换行…

chatgpt赋能python:Python如何优雅地退出程序执行

Python如何优雅地退出程序执行 Python是一种非常强大的编程语言,它易于学习和使用,并拥有许多有用的功能和库。在Python编程中,经常需要退出程序执行。本文将介绍一些Python中退出程序执行的方法,并探讨它们的优缺点。 1. 使用s…

数据库中的SQL是如何执行的?

简介 参考文献:03丨学会用数据库的方式思考SQL是如何执行的 以oracle和MySQL为例,讲解了sql是怎么被执行的,并且对比了执行过程中,oracle和MySQL的异同。 个人感觉,讲解的核心是SQL执行时的缓存机制。 Oracle中的s…

算法刷题-字符串-重复的子字符串

KMP算法还能干这个 459.重复的子字符串 力扣题目链接 给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。 示例 1: 输入: “abab” 输出: True 解释: 可由子字符串 “ab” 重复两…

计算机网络面试

计算机网络面试 OSI七层模型 七层网络体系结构各层的主要功能: 应用层:为应用程序提供交互服务。在互联网中的应用层协议很多,如域名系统DNS,支持万维网应用的HTTP协议,支持电子邮件的SMTP协议等。表示层:主要负责数据格式的转换,如加密解密、转换翻译、压缩解压缩等。…

Navicat如何连接MySQL

市面上有很多数据库连接工具,比如Navicat、SQLYog、WorkBench等,用的比较多的,比较好用的,还是Navicat。现在我们就来说说Navicat如何连接Mysql,此文仅适用于小白,大神可略过。 1.打开Navicat,点击左上角的【连接】按钮…

(十)异步-什么是异步(1)

一、什么是异步 启动程序时,系统会在内存中创建一个新的进程。 进程: 构成运行程序的资源的集合。这些资源包括虚地址空间、文件句柄和程序运行所需的其他许多东西。 在进程内部,系统创建了一个称为线程的内核对象,它代表了真正…