Spring中Bean对象的作用域和生命周期详解

news2024/11/15 13:42:21

Spring作为一个具有众多工具方法的IoC容器,其核心功能就是Bean对象的存储和取出,那么学习Bean对象的作用域和生命周期能让我们更清楚地了解Bean对象在Spring容器中的整个加载过程!

一,案例演示(Bean对象的修改)

假设现在有一个公共的Bean对象(用Student对象来表示),整个Bean对象需要给用户A和用户B使用,但是A在B使用之前对Student类中的属性进行了修改,那么此时B用户从Spring中拿到的Bean对象是否是预期的对象(期望拿到未被修改过的Bean对象)?

公共的Bean对象:

package com.java.demo.entity;

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

//加上lombok的相关注解减少相关代码量
@Setter
@Getter
@ToString
public class Student {
    //给学生赋予id name 的属性
    private int id;
    private String name;
}

使用Bean方法注解将Bean对象注册到Spring容器中:

package com.java.demo.component;

import com.java.demo.entity.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * 使用该类将 Bean 对象注册到 Spring 容器中
 */

@Component
public class StudentBeans {
    @Bean   //使用方法注解将student对象注册到 Spring 容器中
    public Student student() {
        //给student对象相关属性初始化
        //注意这里是伪代码 不涉及与数据库之间的交互
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        return student;
    }
}

用户A使用并修改Bean对象:

package com.java.demo.controller;

import com.java.demo.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * StudentController1 代表用户A
 * A用户使用Bean对象的同时修改了Bean对象
 */

@Controller
public class StudentController1 {
    @Autowired  //使用属性注入的方式
    private Student student;

    public void printStudent1() {
        System.out.println(student);
        //这里对Bean对象进行修改
        Student myStudent = student;
        student.setName("李四");
        System.out.println("student -> " + student.getName());
        System.out.println("myStudent -> " + myStudent.getName());
    }
}

用户B使用Bean对象:

package com.java.demo.controller;

import com.java.demo.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * StudentController2 代表用户B
 * 用户B使用Bean对象
 */

@Controller
public class StudentController2 {
    @Autowired  //使用属性注入的方式
    private Student student;
    
    public void printStudent2() {
        System.out.println("B用户:student -> " + student.getName());
    }
}

创建启动类进行测试:

package com.java.demo;

import com.java.demo.controller.StudentController1;
import com.java.demo.controller.StudentController2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        //用户A
        //从 Spring 容器中获取 Bean 对象
        StudentController1 studentController1 = context.getBean("studentController1",StudentController1.class);
        //使用 Bean 对象
        studentController1.printStudent1();

        //用户B
        //从 Spring 容器中获取 Bean 对象
        StudentController2 studentController2 = context.getBean("studentController2",StudentController2.class);
        //使用 Bean 对象
        studentController2.printStudent2();
    }
}

 我们预期的结果用户B得到的结果应该是一开始注册到Spring容器中的Bean对象(即name应该是张三),但是结果打印的却是李四,说明此时用户B得到的Bean对象是用户A修改之后的;这是因为在默认不加任何条件控制的情况下,Spring认为Bean对象是一个单例的对象,只有一份,在这个工程中的任何操作都是对同一个Bean对象在操作,这也就是Bean对象作用域的一种——单例模式!

二,Bean对象的作用域

定义:限定程序中变量的可⽤范围叫做作⽤域,或者说在源代码中定义变量的某个区域就叫做作⽤域;⽽ Bean 的作⽤域是指 Bean 在 Spring 整个框架中的某种⾏为模式,⽐如 singleton 单例作⽤域,就 表示 Bean 在整个 Spring 中只有⼀份,它是全局共享的,那么当其他⼈修改了这个值之后,那么另⼀ 个⼈读取到的就是被修改的值。

Bean对象作用域的分类:

Spring容器在初始化一个Bean的实例时,同时会指定该实例的作用域;Spring有6中作用域,最后四种是基于Spring MVC生效的:

  1.  singleton:单例作用域;
  2. prototype:原型作用域(多例作用域);
  3. request:请求作用域;
  4. session:会话作用域;
  5. application:全局作用域;
  6. webSocket:HTTP WebSocket作用域.
    singleton默认情况,出于对性能的考虑
    prototype与单例模式相对,俗称多例模式
    request每次HTTP请求都会创建一个 Bean 对象
    session

    每次Session会话就会共享一个 Bean 对象

    application一个http servlet context 中共享一个 Bean 对象
    webSocket网络长连接

 三,设置作用域(@Scope)

Spring中一般使用@Scope 注解来声明Bean的作用域,对上述案例进行修改,将Bean对象的作用域改成prototype,使得用户B读取到的Bean对象是一开始注册到Spring容器中的未进行修改的对象

@Component
public class StudentBeans {
    @Bean   //使用方法注解将student对象注册到 Spring 容器中
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //声明Bean对象的作用域
    public Student student() {
        //给student对象相关属性初始化
        //注意这里是伪代码 不涉及与数据库之间的交互
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        return student;
    }
}

 这两种方法均可!

 四,Spring(Bean)的执行流程

 

执行流程:spring的执行流程也是Bean的执行流程

  • 启动 Spring 容器
  • 实例化 Bean(分配内存空间,从无到有)
  • 将 Bean 注册到 Spring 容器中(存操作)
  • 将 Bean 装配到需要的类中(取操作)

五,Bean的生命周期

所谓的⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程,我们把这个过程就叫做⼀个对象的⽣命周期;Bean的生命周期分为以下5个部分:
  1. 实例化 Bean(开辟内存空间)
  2. 设置属性(注入属性)
  3. 初始化
    • 各种通知
    • 初始化前置方法
    • 初始化方法(两种实现方式:XML方式,注解方式)
    •  初始化后置方法
  4. 使用B ean 对象
  5. 销毁 Bean 对象

注意:这里的实例化并不等于初始化,实例化是操作系统完成的,操作过程不可人工干预和修改;而初始化是给开发者提供的,在实例化之后进行初始化!

生命周期的演示:

BeanCompoent:

package com.java.demo.component;

import org.springframework.beans.factory.BeanNameAware;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class BeanComponent implements BeanNameAware {

    @Override
    public void setBeanName(String s) {
        System.out.println("执行了通知 BeanName ->  " + s);
    }

    public void myInit() {
        System.out.println("XML 方式初始化");
    }

    @PostConstruct
    public void doPostConstruct() {
        System.out.println("注解初始化方法");
    }

    public void sayHi() {
        System.out.println("执行 sayHi()");
    }

    @PreDestroy
    public void doPreDestroy() {
        System.out.println("执行 doPreDestroy()");
    }
}

 启动类App:

package com.java.demo;

import com.java.demo.component.BeanComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        //1.获取 Spring 上下文对象
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //2.获取 Bean 对象
        BeanComponent beanComponent = context.getBean("beanComponent", BeanComponent.class);
        //3.使用 Bean 对象
        beanComponent.sayHi();
        context.destroy();
    }
}

 

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

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

相关文章

4.搜索辅助功能

ES 既有基本的搜索功能、又有字段类型的精确搜索、分词匹配、范围搜索、坐标搜索、分页查询等等。 4.1 搜索辅助功能 俗话说“工欲善其事,必先利其器”。在介绍ES提供的各种搜索匹配功能之前,我们先介绍ES提供的各种搜索辅助功能。例如,为优化…

【让你的灵感立刻落地】在线代码运行平台InsCode

文章目录官网地址详解1. 导入项目2. 在线演示、在线修改3. 发布作品参考InsCode 是一个在线代码运行平台,可以在线上运行代码,并且支持多种语言,同时还可以在线修改和提交代码,支持发布和分享项目。InsCode 平台在编写博客、演示项…

二叉树练习题(递归展开图详解哦)

全文目录引言单值二叉树题目描述及思路实现二叉树的最大深度题目描述及思路实现翻转二叉树题目描述及思路实现相同的树题目描述及思路实现总结引言 前面我们介绍了二叉树的相关基础知识,并且了解到二叉树的表示有两种结构:顺序结构与链式结构。即&#…

手把手教您注册/使用Claude

文章目录注册slack注意事项最近几天出现了一个很火的AI聊天项目——Claude,据说可以媲美ChatGPT,最主要的就是可以很好的解决我们国内的使用痛点,可以完全免费无限制的使用,下面就和大家分享一下正确的注册和使用Claude的流程&…

想成为一名【黑客】,你该如何快速的入门?

假设你有一台个人电脑,或者可以访问一台电脑,那么你就可以着手【黑客】技能的学习了。【黑客】文化演化而来的的时候,电脑是很昂贵的,个人不能拥有他们。所以最重要的一个步骤就是新手可以拥有一台属于自己的电脑,新手…

【Cisco Packet Tracer| 一.交换机配置模式与基本参数配置】

文章目录一.交换机的多种模式以及切换1.如何进入到交换机配置的命令行用户界面(Command Line Interface)2.普通模式模式3.特权用户模式4.全局配置模式5.模式切换图二.交换机名称,口令等设置1.全局模式下-交换机改名2.接口模式下-配置端口速度和工作模式2.1配置端口速…

项目8:用户注册和登录的前后端联调

项目8:用户注册和登录的前后端联调 1.前端项目使用 2.前端项目注册模块 3.后端完成项目注册 4.前端项目登录模块 5.后端完成项目登录 6.用户认证(校验用户是否登录) 项目8:用户注册和登录的前后端联调 1.前端项目使用 直接…

20230413在CV1826平台配置开机自启动程序

20230413在CV1826平台配置开机自启动程序 2023/4/13 10:51 1、项目需求:硬件需要测量摄像头开机之后的电压/时钟信号,但是不想每次开机的时候都通过adb连接cv1826来开启摄像头。 C:\Users\Sun>adb shell / # / # cd /mnt/ /mnt # /mnt # ls -l total …

Go 语言性能优化指南

编写高性能的 Go 程序~ 前言: 继上次课程的高质量编程内容讲解,本次课程主要介绍了在满足正确性、可靠性、健壮性、可读性等质量因素的前提下提高程序效率的性能优化建议;性能优化分析工具;以及性能调优的实战案例,分…

叶酸聚乙二醇羟基FA-PEG-OH;一文带你了解高分子试剂OH-PEG-Folate

FA-PEG-OH,叶酸-聚乙二醇-羟基 中文名称:叶酸聚乙二醇羟基 英文名称:FA-PEG-OH HO-PEG-FA Folate-PEG-OH 性状:黄色液体或固体,取决于分子量 溶剂:溶于水,DMSO、DMF等常规性有机溶剂 活性基…

城市地下综合管廊安全运营与智慧管控的分层架构研究

安科瑞 李亚俊 1、引言 1833年,市政管线综合管廊在巴黎城市地下建成至今,经过百年来的探索、研究、改良和实践,法国、英国、德国、俄罗斯、日本、美国等发达国家的管廊规划建设与安全运维体系已经日臻完善,截止目前,…

《花雕学AI》17:关注提示工程—本世纪最重要的技能可能就是与AI人工智能对话

本文目录与主要结构 引言:介绍提示工程的概念和背景,说明为什么它是本世纪最重要的技能之一。 正文: 一、提示工程的基本原理和方法:介绍什么是提示、如何设计和优化提示、如何使用提示与语言模型进行交互。 二、提示工程的应用和…

Direct3D 12——混合——混合

混合运算 typedef enum D3D12_BLEND_OP {D3D12_BLEND_OP_ADD 1, //添加源 1 和源 2。D3D12_BLEND_OP_SUBTRACT 2,//从源 2 中减去源 1。D3D12_BLEND_OP_REV_SUBTRACT 3,//从源 1 中减去源 2。D3D12_BLEND_OP_MIN 4,//查找源 1 和源 2 的最小值。D3D12_BLEND_OP_MAX 5//查…

【云原生|Docker】13-Docker-compose详解

【云原生Docker】13-Docker-compose详解 文章目录【云原生Docker】13-Docker-compose详解前言docker-compose简介docker-compose安装docker-compose基本示例Docker Compose常用命令说明Docker Compose文件详解versionserviceimagebuildcommandlinksexternal_linksportsexposeen…

Win11的两个实用技巧系列之找不到wifi网络的解决方法、双系统开机选择系统方法

Win11装了VMware后找不到wifi网络的解决方法 有用户在电脑上安装了VMware虚拟机来使用的时候,发现虚拟机中无法进行无线网络的连接了,本文就为大家带来了详细的解决方法,一起看看吧 Win11装了VMware后找不到wifi网络的解决方法教学分享。有用…

助力信创国产化,Solon v2.2.9 发布

Solon 是一个高效的 Java 应用开发框架:更快、更小、更简单。它不是 Spring、没有使用 Servlet、JavaEE 接口,是一个有自己接口标准的开放生态。可以为应用软件国产化提供支持,助力信创建设。 150来个生态插件,覆盖各种不同的应用…

【SSM框架】Spring更简单的存储对象

Spring更简单的存储对象将Bean对象简单存储到Spring容器中使用五大类注解来存储Bean对象使⽤ Controller 存储 bean 对象使⽤ Service 存储 bean 对象使⽤ Repository 存储 bean 对象使⽤ Component 存储 bean 对象使⽤ Configuration为什么要有五大类注解五大类注解的关系五大…

【C++初阶】类与对象(一)

文章目录一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装1 、访问限定符2.封装五、类的作用域六、类的实例化七、类对象模型1.探究存储方式2.结构体内存对齐规则八、this指针1、this指针的引出2.this指针的特性八、C语言和C实现Stack的对比总…

漏洞挖掘小技巧(一)

Swagger UI反射XSS Swagger UI是目前最流行的RestFul接口API文档和测试工具。 首先写一个 json的 XSS 负载 https://gist.githubusercontent.com/ramkrivas/c47c4a49bea5f3ff99a9e6229298a6ba/raw/e2e610ea302541a37604c7df8bcaebdcb109b3ba/xsstest.json回到Swagger UI&…

轮廓特征属性及应用

轮廓特征属性及应用 1)凸包 凸包(Convex Hull)是一个计算机几何图形学中的概念, 简单来说, 给定二维平面点集, 凸包就是能够将最外层的点连接起来构成的凸多边形, 它能够包含点集中所有的点。物体的凸包检测常应用在物体识别、手势识别及边界检测等领域。 寻找凸包—cv2.co…