Bean 的作用域和生命周期

news2024/11/17 9:57:22

目录

一、 Bean 的作用域

1. 安装Lombok插件

1.1 Lombok 简介

1.2 Lombok 安装

 2. 创建一个 User 对象,然后将 User 对象 存储到 Spring 容器中

2.1 创建User 对象

2.2 将User 对象存储到 Spring 中

2.3 修改 User 对象中的属性,然后看结果(两个对象是否都被修改)

2.4 获取 Bean 对象,看此对象是修改前的还是后的

2.5 运行结果:

2.6 结论:

3. Spring Bean 的6种作用域

3.1 作用域详解

3.2 代码设置 Bean 的作用域

 二、Spring 的执行流程和 Bean 的生命周期

1. 启动 spring 容器:

 2. 根据配置完成 Bean 对象的初始化:

 3. 将 Bean 对象存储到 Spring 容器中:

 4. 装配 Bean 的属性:

 3.2 Bean 的生命周期详解

 3.3 Bean 的初始化详解


前言

    上一篇文章已经介绍了如何更加简单的存储和获取 Bean 对象,那么 Bean 对象在 Spring 容器中的生命周期又是什么时期,是一直跟随 Spring 容器呢,还是可以随时创建和销毁的呢。所以这篇文章详细介绍一下 Bean 对象的作用域以及生命周期。

一、 Bean 的作用域

1. 安装Lombok插件

1.1 Lombok 简介

    Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。

1.2 Lombok 安装

(1)在pom.xml 配置文件中添加依赖:

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
            <scope>provided</scope>
        </dependency>

(2)在开发工具中安装 Lombok 插件:

 (3)Lombok 的使用:

 2. 创建一个 User 对象,然后将 User 对象 存储到 Spring 容器中

2.1 创建User 对象

package com.java.demo.enity;

import com.sun.javafx.binding.StringFormatter;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

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

2.2 将User 对象存储到 Spring 中

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 user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

2.3 修改 User 对象中的属性,然后看结果(两个对象是否都被修改)

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 {
    @Autowired
    private User user;

    public void printUser() {
        System.out.println(user);
        //修改 User
        User myUser = user;
        myUser.setName("良月初十" + myUser);
        System.out.println("myUser -> " + myUser);
        System.out.println("user -> " + user);
    }
}

2.4 获取 Bean 对象,看此对象是修改前的还是后的

package com.java.demo.controller;

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

import javax.annotation.Resource;

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

    public void printUser2() {
        System.out.println("user -> " + user);

    }
}
import com.java.demo.controller.UserController;
import com.java.demo.controller.UserController2;
import com.java.demo.enity.User;
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();
    }
}

2.5 运行结果:

2.6 结论:

    其实这个现象和SE 阶段学习的浅拷贝的现象是一样的,就是一个引用指向了另一个引用所指向的对象,之后改变对象的值,两个引用所指向的对象都会发生改变。

    我的预期是当一个 Bean 对象存储到了 Spring 容器中之后,一个程序猿拿到这个对象进行修改之后,当另一个程序猿再拿到这个对象还是原来的值,此时才是正常的情况。但是实际结果 这个 Bean 对象只有在整个 Spring 容器中只存储了一份,多个人进行修改的时候此时 这个对象也会随着一起改变。

    所以 Bean 的作用域:默认是单例模式(在整个Spring容器中只有一份)

    这也就意味着在任何一个地方修改 Bean 的值再去获取这个对象都是修改后的值。但是为啥又说默认是单例模式呢? 也就是 Bean 对象的作用域是可以进行设置的(不仅仅只有一种作用域)

3. Spring Bean 的6种作用域

3.1 作用域详解

     Spring 容器在初始化一个 Bean 对象的时候,同时会指定该对象的作用域,如果不进行设置,默认就是单例模式。

1. singleton :单例模式 (spring 要保证性能,此时进行初始化就只有一份对象)

    使用场景:一般用无状态的 Bean 适合使用该模式(无状态:Bean 对象的属性 在整个作用域中不需要被修改)

2. prototype:原型模式(多例作用域)(每次获取 Bean 时,都会重新生成一个 Bean 对象,所以此时性能不高)

    使用场景:一般有状态的 Bean 适合使用该模式

3. request:请求模式 (每次http请求都会创建一个 Bean 对象,类似于多例模式)

    使用场景:一次HTTP的请求和响应共享的 Bean 对象 适用于 该模式。

4. session:会话模式 (在一个HTTP session 中,使用一个 Bean 对象)(如:我进入了学校官网的教务系统,在退出教务系统之前我的多次http请求都是共享一个 Bean 对象的)

    使用场景:在一个用户会话中一般使用该种模式。

   (也就是说session模式对 Bean 对象的共享程度 比 request 模式 的 程度高)

5. application:全局模式 (一个 http servlet Context中会只使用一个 Bean 对象)

    如:

    如果只是一个context,此时就会使用一个 Bean 对象,如果有多个 context 对象,此时就是 一个 context 对象 对应一个 Bean 对象。

    使用场景:Web级别的应用的上下文信息。(获取一个Spring 容器)

6. websocket:HTTP WebSocket 模式 (每一个WebSocket的会话对应着一个 Bean 对象) 

    如:在网页版的电商软件的右下角的那个客服咨询就是一个 WebSocket会话(WebSocket 就是Socket的一个变种, 就是一个web 的长连接)

    使用场景:只适用于 Spring WebSocket 项目。

    注:前两种模式是 Spring 普通项目的模式,后四种模式适用于 Spring Web 项目中。

3.2 代码设置 Bean 的作用域

1. 直接设置值:@Scope("prototype")
2. 使⽤常量设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

    注:设置作用域的时期是在Bean 对象刚存储进来的时候就需要设置好了作用域,而不是在获取Bean 对象的时候才 设置作用域。

    如下图所示:(直接设置值)

   (使⽤常量设置)

 二、Spring 的执行流程和 Bean 的生命周期

1. 启动容器

加载配置文件(类加载路径下的 spring-config.xml)

2. 根据配置完成 Bean 对象的初始化

扫描 com.java.demo 包(包含底下所有的子包),然后看哪些包中的类有:五大 类注解

3. 将 Bean 对象存储到 Spring 容器中如果有五大 类注解,就会将这个类实例化,存储到 Spring 容器中
4. 装配 Bean 的属性如果 Bean 对象需要使用其他 Bean 对象作为属性,可以使用 @Autowired 和 @Resource 注解来实现对象的装配

1. 启动 spring 容器:

 2. 根据配置完成 Bean 对象的初始化:

 3. 将 Bean 对象存储到 Spring 容器中:

 4. 装配 Bean 的属性:

 3.2 Bean 的生命周期详解

    生命周期:就是一个对象从有到无的一个整个的生命过程,称作一个对象的生命周期。

Bean 的生命周期大概分为5个部分:

1. 实例化 Bean 对象(给 bean 分配一块内存)
2. 设置属性(Bean 对象的注入和装配)
3. Bean 对象的初始化(这块下面进行详细介绍)
4. 使用 Bean 对象
5. 销毁 Bean 对象

    注:Bean 对象的实例化 和 初始化 不是一个概念,不可以混为一谈,实例化是分配内存空间的过程,初始化是通过执行自己的各种方法完成了构造一个完整的 Bean 对象的过程。

    所以实例化和设置属性的时机是在初始化 Bean 对象之前。

 (实例化就像是先买房,而初始化是装修,是需要先买房,再装修的)和JVM运行的流程是一样的关于JVM执行流程可以参考文章:JVM(Java虚拟机)详解 - 良月初十♧的博客 

    代码演示:

3.3 Bean 的初始化详解

  •  各种通知: 实现各种 Aware 方法,例如:BeanNameAware,BeanFactoryAware,ApplicationContextAware 的接口方法
  • 初始化前置方法:执行后 BeanPostProcessor 
  • 执行初始化方法: 1. @PostConstruct (依赖注入操作之后被执行)-->  注解方式                                                  2. init-method 方法(如果设置了才会执行)-->  init - method 方法 
  • 执行 BeanPostProcessor 初始化的后置方法

    总结:Bean 对象生命周期(从有到无的过程):

1、 开辟内存空间  (注:实例化 ≠ 初始化)
2、 设置属性 (上述两步都在实例化之前)

3、 初始化  

       3.1  各种通知(初始化了一部分内容就开始通知一下)

       3.2  初始化的前置方法

       3.2  初始化方法  (两种实现方法:xml方式,注解方式)

       3.3  初始化后置方法()

4、 使用 和 销毁 Bean 对象

 

代码演示 Bean 对象的 初始化步骤:

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);
    }
    /*xml 初始化方法*/
    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("do PreDestroy");
    }
}
//在启动类中
ClassPathXmlApplicationContext context = new
                ClassPathXmlApplicationContext("spring-config.xml");
        BeanComponent component = context.getBean("beanComponent",
                BeanComponent.class);
        component.sayHi();
        component.doPreDestroy();

    运行结果:

 

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

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

相关文章

概率论的学习和整理--番外12:2个概率选择比较的题目

目录 1 题目 2 结论 3 算法 3.1 错误算法 3.2 算法1&#xff0c;用期望的方式解方式 3.3 算法2&#xff0c;直接解方程 3.4 算法3&#xff0c;用递归--等比数列求和来算 4 上述比较的意义-回到问题本身 1 题目 题目 3个A合成1个B 方案1&#xff1a;1/4 几率返还一个A…

【ONE·Linux || 地址空间与进程控制(二)】

总言 进程地址空间和进程控制相关介绍。 文章目录 总言2、进程控制续2.3、进程等待2.3.1、为什么需要进程等待2.3.2、阻塞式等待2.3.2.1、使用wait2.3.2.2、使用waitpid2.3.2.3、参数status基本介绍 2.3.3、一些细节与问题</font>2.3.3.1、进程独立性说明2.3.3.1、父进程…

【网络安全带你练爬虫-100练】第13练:文件的创建、写入

目录 目标&#xff1a;将数据写入到文件中 网络安全O 目标&#xff1a;将数据写入到文件中 开干 &#xff08;始于颜值&#xff09;打开一个&#xff0c;没有就会创建 with open(data.csv, modew, newline) as file: &#xff08;忠于才华&#xff09;开始写入数据 writer cs…

LinuxC/C++开发工具——make/makefile和gdb

linux开发工具 前言Linux项目自动化构建工具&#xff08;make/makefile&#xff09;makefile文件的组成如何使用make.PHONY关键字 项目清理 gdb调试器背景使用list&#xff08;l&#xff09;调试命令break&#xff08;b&#xff09;&#xff1a;设置断点info break&#xff1a;…

[STL] vector 模拟实现详解

目录 一&#xff0c;准备工作 二&#xff0c;push_back 1&#xff0c; 关于引用 2. 参数const 的修饰 补充 三&#xff0c;迭代器实现 四&#xff0c;Pop_back 五&#xff0c;insert 1. 补充——迭代器失效 六&#xff0c; erase 七&#xff0c;构造函数 1. 迭代…

合并当天Log

1.原因&#xff0c; 我们程序运行Log很多时&#xff0c;如果因为要写Log话费很多时间&#xff0c;这时我们可以把log保存按照更短的时间保存&#xff0c;比如一分钟一个Log,一个小时一个log&#xff0c;。。。。但我们查看Log时很麻烦&#xff0c;需要把分散的Log合并起来的工…

移动端深度学习部署:TFlite

1.TFlite介绍 &#xff08;1&#xff09;TFlite概念 tflite是谷歌自己的一个轻量级推理库。主要用于移动端。 tflite使用的思路主要是从预训练的模型转换为tflite模型文件&#xff0c;拿到移动端部署。 tflite的源模型可以来自tensorflow的saved model或者frozen model,也可…

ylb-定时任务task

总览&#xff1a; 在api模块service包&#xff0c;创建IncomeService类&#xff1a;&#xff08;收益计划 和 收益返还&#xff09; package com.bjpowernode.api.service;public interface IncomeService {/*收益计划*/void generateIncomePlan();/*收益返还*/void generate…

基于mysql+java+springboot的福州大学生就业求职系统(含源码+系统演示视频)

1、系统演示视频&#xff1a;基于JavaMySQLspringboot的福州大学生就业求职系统演示视频 2、系统源码&#xff1a;系统源码链接 文章目录 一、需求分析1、公司招聘2、简历管理3、交流咨询 二、福州大学就业求职服务平台简介1.福州大学就业求职服务平台主要功能1.1.个人求职功能…

小黑子—JavaWeb:第一章 - JDBC

JavaWeb入门1.0 1. javaweb介绍2. 数据库设计2.1 约束2.2 表关系2.3 多表查询2.3.1 内连接&#xff08;连接查询&#xff09;2.3.2 外连接&#xff08;连接查询&#xff09;2.3.3 子查询 2.4 事务 3. JDBC3.1 JDBC 快速入门 4 JDBC API详解4.1 DriverManager4.2 Conncetion4.3 …

13_Linux无设备树Platform设备驱动

目录 Linux驱动的分离与分层 驱动的分隔与分离 驱动的分层 platform平台驱动模型简介 platform总线 platform驱动 platform设备 platform设备程序编写 platform驱动程序编写 测试APP编写 运行测试 Linux驱动的分离与分层 像I2C、SPI、LCD 等这些复杂外设的驱动就不…

吴恩达ML2022-用于手写数字识别的神经网络

1 用到的包 导入在这个分配过程中需要的所有包。 Numpy 是使用 Python 进行科学计算的基本软件包。Matplotlib 是在 Python 中绘制图形的流行库。tensorflow是一种流行的机器学习平台。 import numpy as np import tensorflow as tf from tensorflow.keras.models import Se…

Java对象导论

对象具有状态、行为和标识。每个对象都可以拥有内部数据&#xff08;它们给出了该对象的状态&#xff09;和方法&#xff08;它们产生的行为&#xff09;&#xff0c;并且每个对象在内存中都有一个唯一的地址&#xff08;标识&#xff09;。 抽象过程就是在问题空间元素和解空…

Macbook下提升开发效率的几个小工具

最近倒腾mac笔记本&#xff0c;记录下一些高效率的工具吧。 首先就是alfred&#xff0c;内置可以自定义各种快捷命令查找&#xff0c;配合Dash来快速查找C系统API&#xff0c;其实Dash中包含了各种编程所需API文档&#xff0c;值得下载。 以前我都是直接查看cppreference.c…

【分享】Redis的五种基本数据类型和应用场景

前言&#xff1a; Redis支持五种基本数据类型&#xff1a; String&#xff08;字符串类型&#xff09;&#xff1a;可以是普通字符串&#xff0c;也可以是整数或浮点数值。可以设置过期时间&#xff1b;可以对字符串进行append、get、set、incr、decr等操作。Hash&#xff08…

【C++】位图和布隆过滤器

文章目录 位图概念难点代码 布隆过滤器概念插入查找删除优缺点代码 位图 概念 所谓位图&#xff0c;就是用每一个比特位位来存放某种状态&#xff0c;适用于海量数据&#xff0c;数据无重复的场景。通常是用来判断某个数据存不存在的。 给40亿个不重复的无符号整数&#xff…

buu_Misc总结2

目录 百里挑一 exiftool: [SUCTF2018]followme grep工具使用&#xff1a; [安洵杯 2019]Attack mimikatz工具使用&#xff1a; 百里挑一 打开文件是流量包&#xff0c;发现里面有很多图片 导出http 另存一个文件夹&#xff0c;里面很多图片&#xff0c;啥也看不出来 &…

医用影像技术

1.X光和CT原理 X光和CT&#xff08;计算机断层扫描&#xff09;都是医学成像技术&#xff0c;用于诊断和治疗。它们的原理如下&#xff1a; X光原理&#xff1a; X光是一种电磁辐射&#xff0c;与可见光类似&#xff0c;但具有更高的能量。当X光通过人体或物体时&#xff0c;…

创作一周年纪念日【道阻且长,行则将至】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; 技术之外的往事 &#x1f383;所处时段&#xff1a; 大学生涯[1/2] 文章目录 一、起点一切皆有定数 二、成果尽心、尽力 三、相遇孤举者难起&#xff0c;众行者易趋 四、未来长风破浪会有时&#xff0c;直挂云…

[MySQL]MySQL表中数据的增删查改(CRUD)

[MySQL]MySQL表中数据的增删查改(CRUD) 文章目录 [MySQL]MySQL表中数据的增删查改(CRUD)1. 新增数据1.1 单列插入1.2 多列插入1.3 插入否则更新1.4 替换 2. 基本查询数据2.1 全列查询2.2 指定列查询2.3 查询字段为表达式2.4 为查询结果指定别名2.5 结果去重2.6 where子句2.7 or…