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

目录

前言

案例

案例分析

作用域的定义 

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
     

流程图如下:

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

贝锐花生壳:无需公网IP、简单3步,远程访问群晖NAS

面对NAS远程访问难题&#xff0c;贝锐花生壳一招搞定&#xff01;并且无需公网IP、简单3步&#xff0c;即可实现固定域名远程访问NAS。 步骤1&#xff1a; 目前&#xff0c;群晖NAS已在套件中心内置花生壳客户端。 浏览器进入群晖NAS的DSM管理界面&#xff0c;点击【套件中心】…

SSM大学生社团信息管理系统-99953,(免费领取源码)计算机毕业设计选题开题+程序定制+论文书写+答辩ppt书写 包售后 全流程

SSM大学生社团信息管理系统APP 摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;高校当然也不能排除在外。大学生社团信息管理系统APP是以实际运用为开发背景&#xff0c…

[Python程序打包: 使用PyInstaller制作单文件exe以及打包GUI程序详解]

文章目录 概要Python 程序打包—使用 Pyinstaller 打包 exePython程序打包—使用Pyinstaller打包GUI程序Python程序打包—使用 Pyinstaller 设置 exe 图标小结 概要 使用PyInstaller工具将Python程序打包成可执行&#xff08;EXE&#xff09;文件。将Python程序打包成EXE的好处…

unittest指南——不拼花哨,只拼实用

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

看完就会,从抓包到接口测试的全过程解析【1500字保姆级教程】

一、为什么抓包 1、从功能测试角度 通过抓包查看隐藏字段 Web 表单中会有很多隐藏的字段&#xff0c;这些隐藏字段一般都有一些特殊的用途&#xff0c;比如收集用户的数据&#xff0c;预防 CRSF 攻击&#xff0c;防网络爬虫&#xff0c;以及一些其他用途。这些隐藏字段在界面…

从裸机启动开始运行一个C++程序(十四)

前序文章请看&#xff1a; 从裸机启动开始运行一个C程序&#xff08;十三&#xff09; 从裸机启动开始运行一个C程序&#xff08;十二&#xff09; 从裸机启动开始运行一个C程序&#xff08;十一&#xff09; 从裸机启动开始运行一个C程序&#xff08;十&#xff09; 从裸机启动…

socket can中是如何根据 结构体can_bittiming_const中的字段 计算bitrate的?

在 SocketCAN 中&#xff0c;can_bittiming_const 结构体用于表示 CAN 总线的定时参数&#xff0c;包括位率&#xff08;bitrate&#xff09;的计算。can_bittiming_const 包含了许多与位率相关的参数&#xff0c;其中一些参数用于计算实际的位率。 下面是一些与位率计算相关的…

js实现数组的上下移动

思路&#xff1a;上移表示index索引位置减去1&#xff0c;下移表示index索引位置增加1。使用数组的splice方法实现。例如上移&#xff1a;splice(元素当前索引位置&#xff0c;1(删除1个元素)&#xff0c;‘元素当前索引位置 - 1’)。

ruoyi 若依框架采用第三方登录

在项目中&#xff0c;前后端分离的若依项目&#xff0c;需要通过统一认证&#xff0c;或者是第三方协带认证信息跳转到本系统的指定页面。需要前后端都做相应的改造&#xff0c;由于第一次实现时已过了很久&#xff0c;再次重写时&#xff0c;发现还是搞了很长时间&#xff0c;…

任意分圆环下的 RLWE:如何产生正确的噪声分布

参考文献&#xff1a; [Con09] Conrad K. The different ideal[J]. Expository papers/Lecture notes. Available at: http://www.math.uconn.edu/∼kconrad/blurbs/gradnumthy/different.pdf, 2009.[LPR10] Lyubashevsky V, Peikert C, Regev O. On ideal lattices and learn…

友思特分享 | Neuro-T:零代码自动深度学习训练平台

来源&#xff1a;友思特 智能感知 友思特分享 | Neuro-T&#xff1a;零代码自动深度学习训练平台 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 工业自动化、智能化浪潮涌进&#xff0c;视觉技术在其中扮演了至关重要的角色。在汽车、制造业、医药、芯片、食品等行业…

日本服务器访问速度和带宽有没有直接关系?

​  对于许多网站和应用程序来说&#xff0c;服务器的访问速度是至关重要的。用户希望能够快速加载页面、上传和下载文件&#xff0c;而这些都与服务器的带宽有关。那么&#xff0c;日本服务器的访问速度和带宽之间是否存在直接关系呢? 我们需要了解什么是带宽。带宽是指网络…

NVMe-oF E-JBOF设计解析:WD RapidFlex网卡、OpenFlex Data24

OpenFlex Data24 NVMe-oF Storage Platform WD的SN840 NVMeSSD新品并没有太吸引我注意&#xff0c;因为它还是PCIe 3.0接口的&#xff0c;要知道Intel的PCIe 4.0 SSD都已经推出了。 但上面这个NVMe-oF&#xff08;NVMe over Fabric&#xff09;EBOF&#xff08;区别于普通JBO…

中国上市公司漂绿程度及其同构指数(多种测算方法,2012-2022年)

数据简介&#xff1a;20 世纪 90 年代开始&#xff0c;国际上关于绿色市场和绿色管理的学术文献日渐丰富&#xff0c;众多企业积极响应碳排放政策的号召&#xff0c;但其中有多少企业是实实在在的进行碳减排技术创新&#xff0c;又有多少企业打着绿色低碳行为的口号来吸引眼球、…

浏览器缓存、本地存储、Cookie、Session、Token

目录 前端通信&#xff08;渲染、http、缓存、异步、跨域&#xff09; HTTP与HTTPS&#xff0c;HTTP版本、状态码 请求头&#xff0c;响应头 缓存 强制缓存&#xff1a;Cache-Control:max-age&#xff08;HTTP1.1&#xff09;>Expires&#xff08;1.0&#xff09; js、…

【Spring篇】JDK动态代理

目录 什么是代理&#xff1f; 代理模式 动态代理 Java中常用的代理模式 问题来了&#xff0c;如何动态生成代理类&#xff1f; 动态代理底层实现 什么是代理&#xff1f; 顾名思义&#xff0c;代替某个对象去处理一些问题&#xff0c;谓之代理&#xff0c;那么何为动态&a…

力扣 3. 无重复字符的最长子串

题目 题解 方法 public static int lengthOfLongestSubstring(String s) {HashSet<Character> charSet new HashSet<Character>();int i 0,l0,max0;for (int j 0; j < s.length(); j) {while (charSet.contains(s.charAt(j))) {charSet.remove(s.charAt(l…

python -opencv 轮廓检测(多边形,外接矩形,外接圆)

python -opencv 轮廓检测(多边形&#xff0c;外接矩形&#xff0c;外接圆) 边缘检测步骤: 第一步&#xff1a;读取图像为灰度图 第二步&#xff1a;进行二值化处理 第三步&#xff1a;使用cv2.findContours对二值化图像提取轮廓 第三步&#xff1a;将轮廓绘制到图中 代码如下…

科学上网也clone不全PX4?

一、问题 已经科学上网&#xff0c;下载PX4固件 git clone https://github.com/PX4/Firmware.git --recursivePX4大框架 clone 下来了&#xff0c;但是内部的子模块很多没有&#xff0c;报了很多 Fatal&#xff0c;例如 fatal: clone of https://github.com/px4/cyclonedds …

行情分析 - - 加密货币市场大盘走势(11.24)

大饼昨日震荡幅度很小&#xff0c;而今天延续昨日的空头思路。当然如果从MACD日线来看&#xff0c;处于上涨趋势&#xff0c;稳健的可以选择观望等待。空头思路是因为目前EMA21均线和EMA55均线依然保持很远&#xff0c;最近两个月BTC上涨40%&#xff0c;而最近持续保持高位很快…