Spring框架学习 -- Bean的生命周期和作用域

news2024/11/15 20:10:48

目录

前言

案例

案例分析

作用域的定义 

Bean对象的6种作用域 

Singleton

prototype

设置作用域 

​编辑延迟初始化

Spring的执行流程 

Bean的生命周期


前言

        我们可以类比一下普通变量的生命周期和作用域, 大多数变量的生命周期和作用域都被限定在了花括号内 {}, 除了这个大括号, 这个变量也就会被销毁, 与之对应的内存也会被JVM回收.

        对于类中的变量, 即使是出了{}, 也仍然能被访问到.

        前面的内容是如何存储和获取Bean对象, 因此spring中最核心的资源就是Bean对象, 那么Bean的作用域是怎么样的呢?

        下面我们通过一个案例来演示一下:

案例

        假设现在有一个公共的Bean对象提供给用户A和用户B使用, 然后在使用的图中,用户A 却悄咪咪的修改了公共的Bean资源, 导致B在使用的时候发生了预期之外的逻辑错误.

        下面是代码实现:

        首先我们实现Bean对象所属的类:

public class User {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

        创建Bean对象:

@Component
public class Users {
    @Bean
    public User getUser() {
        User user = new User();
        user.setAge(18);
        user.setName("如花");
        return user;
    }
}

        属性注入:

// controller1 相当于A

@Controller
public class Controller1 {
    @Autowired
    public User user;

    public void useUser() {
        User user1 = user;
        System.out.println("公共类原来的名字为:" + user1.getName());
        System.out.println("A 使用之前将其修改为 翠花");
        user1.setName("翠花");
        System.out.println("现在公共类的名字为:" + user1.getName());
    }
}
@Controller
public class Controller2 {
    @Autowired
    public User user;

    public void userUser() {
        User user1 = user;
        System.out.println("B 使用这个公共Bean类的名字为:" + user1.getName());
        System.out.println("但是B想念的是如花");
    }

}

        添加启动类:

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        Controller1 controllerA = context.getBean("controller1", Controller1.class);
        controllerA.useUser();
        Controller2 controllerB = context.getBean("controller2", Controller2.class);
        controllerB.userUser();
    }
}

-- 输出:

案例分析

        上面问题的原因就是Bean默认情况下是单例状态的(singleton), 也就是所有人使用的都是同一个对象, 之前我们学过单例模式的时候就知道, 使用单例模式可以极大的提高性能, 但是同时也带来了新的安全问题.

        spring中Bean的作用域默认也是singleton的单例模式.

作用域的定义 

        限定程序中变量的可用范围, 我们把这种行为叫做修改作用域, 也就是说这个可用范围对应于这个作用域, 或者说是在源代码中定义变量的某个区域就叫做作用域.

        而Bean的作用域是指在spring整个framework框架中的某个行为, 所以Bean通过不同的行为类型, 来决定定义域, 比如singleton单例作用域, 就表示这个Bean对象是在整个spring中只有一份, 他是全局共享的, 那么其他人修改这个值之后, 另外一个人读取到这个值他就是被修改的值.

        由Spring容器创建的Bean的生存周期被称为Bean的作用域, 默认情况下, 由spring容器创建的所有Bean对象都是Singleton作用域, 换句话说, 针对Bean定义只创建了一个Bean对象, 并有spring容器可以在整个应用程序生存期中使用该实例, 当不同的Bean与不同的层(控制层, 服务层 和 数据访问对象层) 相对应时, 可以使用Singleton作用域.

        spring支持的第二种作用域就是prototype, 类似于java代码中使用new操作来创建Bean对象, 每次需要在容器中或者通过Bean引用其他Bean定义中, 又或者通过显示Bean查询(getBean) 从应用程序中访问Prototype作用域时就会创建他们:

        注意这里的scope = "prototype"

 

Bean对象的6种作用域 

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

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

        注意后面四种是spring MVC中的值, 在普通的spring项目中, 只有目前两种

        下面介绍Spring中常用的两种作用域 >>

Singleton

  • 描述: 该作用域下的Bean在IOC容器中只存在一个实例, 通过ApplicationContext,getBean方法获取的Bean和通过@Autowired或者@Resource等注入的Bean都是同一个对象
  • 场景: 通过无状态的Bean使用该作用域, 无状态表示Bean对象的属性状态不需要更新
  • 备注: Spring默认选择该作用域

prototype

  •  描述: 每次该作用域下的Bean请求都会创建新的实例: 不管是通过spring上下文(ApplicationContext) 或者是通过属性注入Bean, 都是新的对象的实例
  • 场景: 通常有状态的Bean使用该作用域

设置作用域 

         使用@Scope标签就可以用来声明Bean的作用域, 比如设置Bean的作用域, 代码如下:

@Component
public class Users {
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User getUser() {
        User user = new User();
        user.setAge(18);
        user.setName("如花");
        return user;
    }
}

        @Scope标签即可以修饰方法, 也可以修饰类, @Scope有两种设置方法:

  1. 直接设置值: @Scope("prototype")
  2. 使用枚举设置: @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

        或者是在xml配置文件中的Bean对象中添加scope属性:

延迟初始化

        默认情况下, spring容器在启动阶段创建Bean, 该过程被称为预先Bean初始化. 它的有点就是可以尽早发现配置错误. 例如在基于XML文件的配置中, Bean的定义的类属性出现了错别字, 或者引用了一个不可用的Bean定义等.

        但是从另外一方面, 如果存在大量的Bean定义, 或者一些特殊的Bean, 例如Hibernate SessionFactory 或者JPA EntityManagerFactory(这些Bena 的初始化会占用大量时间), 那么初始化可能会降低启动的速度, 一些Bean可能只在特定的场合中使用, 在其他情况下并不被需要, 在这种情况下的话, 预先初始化会导致不必要的内存消耗和性能消耗.

        spring还支持延迟Bean初始化, 如果开发人员将Bean的配置为延迟创建, 那么容器将会延迟Bean的创建, 直到被需要的时候才被创建, 通过从一个已经创建的另外一个Bean中的引用, 或者是显式的调用getBean来查找Bean, 都可以触发Bean的创建.

@Controller
public class Controller1 {
    @Autowired
    public User user;

    public void useUser() {
        User user1 = user;
        System.out.println("公共类原来的名字为:" + user1.getName());
        System.out.println("A 使用之前将其修改为 翠花");
        user1.setName("翠花");
        System.out.println("现在公共类的名字为:" + user1.getName());
    }
}

        例如上述代码, 如果这里的Controller1这个类中的属性user使用的是延迟初始化, 那么只有在使用的时候才会被创建, 例如执行到User1 = user的时候就会被创建和初始化.  

        在基于XML的配置中, 可以在<bean> 标签中使用lazy-init 的字段将Bean设置为延迟初始化.

        如果想在一个XML文件中将所有的Bean对象都定义为延迟初始化, 可以使用<beans>标签的default-lazy-init的字段.

         延迟Bean的创建的优点是加快了容器的启动时间, 并且占用了较少的内存, 但是另外一方面, 如果在元数据中存在Bean的配置错误, 在对方案进行测试之前, 将无法发现这些错误.

        将Bean定义为延迟初始化的时候需要格外注意, 如果其中一个依赖Bean被定义为预先初始化, 那么延迟定义将会没有任何作用, 预先Bean定义在启动期间被处理, 所以它也会触发处理延迟Bean的定义.

Spring的执行流程 

 

 spring的执行流程分为下面几点:

  1. 启动容器, 加载XML配置文件
  2. 根据配置完成Bean初始化:
    1. 添加扫描路径
    2. 识别扫描路径下的类注解, 识别Bean对象
  3. 注册Bean对象到spring容器中

    如果此Bean对象依赖于其他Bean对象的, 可以使用@Autowired和@Resource注解
  4. 装配Bean属性

总结下来就是: 

->启动 Spring 容器

-> 实例化 Bean(分配内存空间,从⽆到有)

-> Bean 注册到 Spring 中(存操作)

-> 将 Bean 装配到需要的类中(取操作, getBean等)

Bean的生命周期

        所谓生命周期就是一个对象从诞生到销毁的整个生命过程, 我们把这个过程就叫做一个对象的生命周期.

        Bean的生命周期分为以下五部分:

  1. 实例化Bean, 为Bean分配内存空间
  2. 设置属性(Bean注入)
  3. Bean初始化
    1. 实现了各种Aware通知的方法, 如BeanNameAware, BeanFactoryAware,ApplicationContextAware
    2. 执行BeanPostProcessor初始化方法
    3. 执行@PostConstruct 初始化方法, 依赖注入后被执行
    4. 指定自己指定的init方法
    5. 执行BeanPostProcessor初始化后置方法
  4. 使用Bean
  5. 销毁Bean
  6. 销毁容器的各种⽅法,如 @PreDestroy、DisposableBean 接⼝⽅法、destroy-method
     

流程图如下:

 

 

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

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

相关文章

OpenCV- 学习笔记(Python)图像处理基础

本专栏&#xff1a;主要记录OpenCV&#xff08;Python&#xff09;学习笔记 OpenCV 图像处理基础 灰度图 import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline ​ imgcv2.imread(cat.jpg) img_gray…

史上最全前端知识点+高频面试题合集,十二大专题,命中率高达95%

前言&#xff1a; 下面分享一些关于阿里&#xff0c;美团&#xff0c;深信服等公司的面经&#xff0c;供大家参考一下。大家也可以去收集一些其他的面试题&#xff0c;可以通过面试题来看看自己有哪里不足。也可以了解自己想去的公司会问什么问题&#xff0c;进行有针对的复习。…

golang学习笔记——接口和继承比较2

接口和继承 现在有一个需要要求大学生和足球运动员掌握英语技能&#xff0c;请问怎么实现? 给运动员和学生结构体添加studyEnglish方法显示是可以的&#xff0c;但是篮球动员和中学生也学习了英语&#xff0c;显示不行。这时&#xff0c;我们可以直接给足球运动员和大学生添加…

ky10 server x86 auditd安装(日志审计系统)

概述 Auditd工具可以帮助运维人员审计Linux&#xff0c;分析发生在系统中的发生的事情。Linux 内核有用日志记录事件的能力&#xff0c;包括记录系统调用和文件访问。管理员可以检查这些日志&#xff0c;确定是否存在安全漏洞&#xff08;如多次失败的登录尝试&#xff0c;或者…

鸿蒙原生应用/元服务开发-AGC分发如何上架HarmonyOS应用

一、上架整体流程 二、上架HarmonyOS应用 获取到HarmonyOS应用软件包后&#xff0c;开发者可将应用提交至AGC申请上架。上架成功后&#xff0c;用户即可在华为应用市场搜索获取开发者的HarmonyOS应用。 配置应用信息 1.登录AppGallery Connect&#xff0c;选择“我的应用”。…

大数据技术之数据安全与网络安全——CMS靶场实训

大数据技术之数据安全与网络安全——CMS靶场实训 在当今数字化时代&#xff0c;大数据技术的迅猛发展带来了前所未有的数据增长&#xff0c;同时也催生了对数据安全和网络安全的更为迫切的需求。本篇博客将聚焦于大数据技术背景下的数据安全与网络安全&#xff0c;并通过CMS&a…

【XSLVGL2.0】如何新增一种语言和词条

XSLVGL2.0 开发手册 【XSLVGL2.0】如何新增一种语言和词条 1、概述2、以外置资源的方式增加词条3、以内置资源的方式增加词条4、使用方法1、概述 本文件旨在介绍新增一种语言词条的方法 2、以外置资源的方式增加词条 假设项目需要增加一种英文的词条。一般地,我们采用国际…

MySQL 有多个普通索引时会取哪一个索引?

我们都知道MySQL在查询时底层会进行索引的优化&#xff0c;假设有两个普通索引&#xff0c;且where 后面也根据这两个普通索引查询数据&#xff0c;那么执行查询语句时会使用到那个索引&#xff1f; 为了方便演示&#xff0c;新建users表&#xff0c;新建idx_name、idx_city这两…

基于Eclipse+Tomcat+Mysql开发的研究生信息教务系统

基于Eclipse的研究生教务系统 项目介绍&#x1f481;&#x1f3fb; 该研究生教务系统是一款集学生信息管理、学院信息维护、学生类别信息维护、专业信息维护、教师信息导入、课程信息导入及老师信息导入等功能于一体的教育管理软件。它以高效、便捷、准确的方式处理教务管理工作…

系列七、事务

一、事务 1.1、概述 事务是数据库操作的基本单元&#xff0c;它是指逻辑上的一组操作&#xff0c;要么都成功&#xff0c;要么都失败。典型场景&#xff1a;转账&#xff0c;例如Jack给Rose转账1000元&#xff0c;转账成功&#xff1a;Jack账户的余额少1000元&#xff0c;Rose…

深度学习+不良身体姿势检测+警报系统+代码+部署(姿态识别矫正系统)

正确的身体姿势是一个人整体健康的关键。然而&#xff0c;保持正确的身体姿势可能很困难&#xff0c;因为我们经常忘记这一点。这篇博文将引导您完成为此构建解决方案所需的步骤。最近&#xff0c;我们在使用 POSE 进行身体姿势检测方面玩得很开心。它就像一个魅力&#xff01;…

关于vs code Debug调试时候出现“找不到任务C/C++: g++.exe build active file” 解决方法

vs code Debug调试时候出现“找不到任务C/C: g.exe build active file” &#xff0c;出现报错&#xff0c;Debug失败 后来经过摸索和上网查找资料解决问题 方法如下 在Vs code的操作页面左侧有几个配置文件 红框里的是需要将要修改的文件 查看tasks.json和launch.json框选&…

四、防火墙-NAT Server

学习防火墙之前&#xff0c;对路由交换应要有一定的认识 NAT Server1.1.基本原理1.2.多出口场景下的NAT Server1.3.源进源出 —————————————————————————————————————————————————— NAT Server 一般对用户提供一些可访问的…

前端学习网站推荐

1.菜鸟教程&#xff08;程序员必备&#xff09;菜鸟教程 - 学的不仅是技术&#xff0c;更是梦想&#xff01; 2.npm库 npm | Home 3.uniapp学习官网 uni-app官网 4.vue官网 快速上手 | Vue.js 5.ECharts图表 Apache ECharts 6.ES6学习 ES6 入门教程 7.Three.js学习 Three.js…

数据结构——单链表(Singly Linked List)

1.链表介绍 链表是一种物理储存上非连续、非顺序的存储结构。数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成&#xff0c;结点可以在运行时动态生成。 对于上图&#xff0c;每一个结点都是一个结…

概率论与数理统计中常见的随机变量分布律、数学期望、方差及其介绍

1 离散型随机变量 1.1 0-1分布 设随机变量X的所有可能取值为0与1两个值&#xff0c;其分布律为 若分布律如上所示&#xff0c;则称X服从以P为参数的(0-1)分布或两点分布。记作X~ B(1&#xff0c;p) 0-1分布的分布律利用表格法表示为: X01P1-PP 0-1分布的数学期望E(X) 0 *…

【前端】让列表像Excel单元格一样编辑

前言 领导说了一堆的话,最后总结一句就是客户很懒,客户的员工更加懒。 本着让别人节省时间的原则,提倡出了让列表和Excal的单元格一样,不仅看数据还可以随时更改数据。 查资料 根据 Jeecg-Vue3 源码介绍,从而知道是基于 Vben Admin 开源项目进行改造的。 因此在 Vben…

web前端之引入svg图片、html引入点svg文件、等比缩放、解决裁剪问题、命名空间、object标签、阿里巴巴尺量图、embed标签、iframe标签

MENU 前言直接在页面编写svg使用img标签引入通过css引入使用object标签引入其他标签参考资料 前言 web应用开发使用svg图片的方式&#xff0c;有如下几种方式 1、直接在页面编写svg 2、使用img标签引入 3、通过css引入 4、使用object标签引入 直接在页面编写svg 在html页面直接…

hive 报错return code 40000 from org.apache.hadoop.hive.ql.exec.MoveTask解决思路

参考学习 https://github.com/apache/hive/blob/2b57dd27ad61e552f93817ac69313066af6562d9/ql/src/java/org/apache/hadoop/hive/ql/ErrorMsg.java#L47 为啥学习error code 开发过程中遇到以下错误&#xff0c;大家觉得应该怎么办&#xff1f;从哪方面入手呢&#xff1f; 1.百…

【CVE-2021-1675】Spoolsv打印机服务任意DLL加载漏洞分析

漏洞详情 简介 打印机服务提供了添加打印机的接口&#xff0c;该接口缺乏安全性校验&#xff0c;导致攻击者可以伪造打印机信息&#xff0c;在添加新的打印机时实现加载恶意DLL。这造成的后果就是以system权限执行任意代码。 影响版本 windows_10 20h2 windows_10 21h1 win…