Spring中Bean的作用域、实例化方式、生命周期、循环依赖问题

Spring中Bean的作用域、实例化方式、生命周期、循环依赖问题

  • 一、Bean的作用域
    • 1.singleton
    • 2.prototype
    • 3.其他scope值
  • 二、Bean的实例化方式
    • 1.通过构造方法实例化
    • 2.通过简单工厂模式实例化
    • 3.通过factory-bean实例化
    • 4.通过FactoryBean接口实例化
    • 5.BeanFactory和FactoryBean的区别
      • (1)BeanFactory
      • (2)FactoryBean
  • 三、Bean的生命周期
    • 1.什么是Bean的生命周期
    • 2.为什么要知道Bean的生命周期
    • 3.Bean的生命周期之5步
    • 4.Bean生命周期之7步
    • 5.Bean生命周期之10步
    • 6.Bean的作用域不同,管理方式不同
    • 7.自己new的对象如何让Spring管理
  • 四、Bean的循环依赖问题
    • 1.什么是Bean的循环依赖
    • 2.singleton下的set注入产生的循环依赖
    • 3. prototype下的set注入产生的循环依赖
    • 4.singleton下的构造注入产生的循环依赖
    • 5.Spring解决循环依赖的机理


一、Bean的作用域

1.singleton

  • 默认情况下,Spring的IoC容器创建的Bean对象是单例的。
  • 默认情况下,Bean对象的创建是在初始化Spring上下文的时候就完成了。

2.prototype

  • 如果想让Spring的Bean对象以多例的形式存在,可以在bean标签中指定scope属性的值为:prototype,这样Spring会在每一次执行getBean()方法的时候创建Bean对象,调用几次则创建几次。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="sb" class="com.gdb.spring6.beans.SpringBean" scope="prototype" />
</beans>

3.其他scope值

  • scope属性的值不止两个,它一共包括8个选项:
    • singleton:默认的,单例。
    • prototype:原型。每调用一次getBean()方法则获取一个新的Bean对象。或每次注入的时候都是新对象。
    • request:一个请求对应一个Bean。仅限于在WEB应用中使用。
    • session:一个会话对应一个Bean。仅限于在WEB应用中使用。
    • global session:portlet应用中专用的。如果在Servlet的WEB应用中使用global session的话,和session一个效果。(portlet和servlet都是规范。servlet运行在servlet容器中,例如Tomcat。portlet运行在portlet容器中。)
    • application:一个应用对应一个Bean。仅限于在WEB应用中使用。
    • websocket:一个websocket生命周期对应一个Bean。仅限于在WEB应用中使用。
    • 自定义scope:很少使用。

二、Bean的实例化方式

  • Spring为Bean提供了多种实例化方式,通常包括4种方式。(也就是说在Spring中为Bean对象的创建准备了多种方案,目的是:更加灵活)

1.通过构造方法实例化

  • 参考我的博客====>Spring对IoC的是实现中的Spring的第一个程序。

2.通过简单工厂模式实例化

  • 第一步:定义一个Bean
package com.gdb.spring6.bean;public class Vip {
}
  • 第二步:编写简单工厂模式当中的工厂类
package com.gdb.spring6.bean;public class VipFactory {public static Vip get(){return new Vip();}
}
  • 第三步:在Spring配置文件中指定创建该Bean的方法(使用factory-method属性指定)
<bean id="vipBean" class="com.gdb.spring6.bean.VipFactory" factory-method="get"/>

3.通过factory-bean实例化

  • 这种方式本质上是:通过工厂方法模式进行实例化。
  • 第一步:定义一个Bean
package com.gdb.spring6.bean;public class Vip {
}
  • 第二步:定义具体工厂类,工厂类中定义实例方法
    • 在这里可以在创建Bean的前后进行加工处理。
package com.gdb.spring6.bean;public class VipFactory {public Vip get(){return new Vip();}
}
  • 第三步:在Spring配置文件中指定factory-bean以及factory-method
<bean id="vipFactory" class="com.gdb.spring6.bean.VipFactory"/>
<bean id="vipBean" factory-bean="vipFactory" factory-method="get"/>

4.通过FactoryBean接口实例化

  • 以上的第三种方式中,factory-bean是我们自定义的,factory-method也是我们自己定义的。
  • 在Spring中,当你编写的类直接实现FactoryBean接口之后,factory-bean不需要指定了,factory-method也不需要指定了。
  • factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。
  • 第一步:定义一个Bean
package com.gdb.spring6.bean;public class Vip {
}
  • 第二步:编写一个类实现FactoryBean接口
package com.gdb.spring6.bean;import org.springframework.beans.factory.FactoryBean;public class VipFactoryBean implements FactoryBean<Vip> {@Overridepublic Vip getObject() throws Exception {return new Vip ();}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {// true表示单例// false表示原型return true;}
}
  • 第三步:在Spring配置文件中配置FactoryBean
<bean id="vipBean" class="com.gdb.spring6.bean.VipFactoryBean"/>
  • FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的。
  • 其实FactoryBean就是一个抽象工厂。
  • 通过FactoryBean这个工厂Bean主要是想对普通Bean进行加工处理。

5.BeanFactory和FactoryBean的区别

(1)BeanFactory

  • Spring IoC容器的顶级对象,BeanFactory被翻译为“Bean工厂”,在Spring的IoC容器中,“Bean工厂”负责创建Bean对象。
  • BeanFactory是工厂。

(2)FactoryBean

  • FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。
  • 在Spring中,Bean可以分为两类:
    • 第一类:普通Bean
    • 第二类:工厂Bean(记住:工厂Bean也是一种Bean,只不过这种Bean比较特殊,它可以辅助Spring实例化其它Bean对象。)

三、Bean的生命周期

1.什么是Bean的生命周期

  • Spring其实就是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。
  • 所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。
  • 什么时候创建Bean对象?
  • 创建Bean对象的前后会调用什么方法?
  • Bean对象什么时候销毁?
  • Bean对象的销毁前后调用什么方法?

2.为什么要知道Bean的生命周期

  • 其实生命周期的本质是:在哪个时间节点上调用了哪个类的哪个方法。
  • 我们需要充分的了解在这个生命线上,都有哪些特殊的时间节点。
  • 只有我们知道了特殊的时间节点都在哪,到时我们才可以确定代码写到哪。
  • 我们可能需要在某个特殊的时间点上执行一段特定的代码,这段代码就可以放到这个节点上。当生命线走到这里的时候,自然会被调用。

3.Bean的生命周期之5步

  • Bean生命周期的管理,可以参考Spring的源码:AbstractAutowireCapableBeanFactory类的doCreateBean()方法。
  • Bean生命周期可以粗略的划分为五大步:
    • 第一步:实例化Bean
    • 第二步:Bean属性赋值
    • 第三步:初始化Bean
    • 第四步:使用Bean
    • 第五步:销毁Bean
  • 需要注意的:
    • 第一:只有正常关闭spring容器,bean的销毁方法才会被调用。
    • 第二:ClassPathXmlApplicationContext类才有close()方法。
    • 第三:配置文件中的init-method指定初始化方法。destroy-method指定销毁方法。(初始化和销毁方法,需要自己在Bean中编写,然后在配置文件中进行配置)

4.Bean生命周期之7步

  • 在以上的5步中,第3步是初始化Bean,如果你还想在初始化前和初始化后添加代码,可以加入“Bean后处理器”。
  • 编写一个类实现BeanPostProcessor类,并且重写before和after方法:
package com.gdb.spring6.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class LogBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean后处理器的before方法执行,即将开始初始化");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean后处理器的after方法执行,已完成初始化");return bean;}
}
  • 在spring.xml文件中配置“Bean后处理器”:
<!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
  • 一定要注意:在spring.xml文件中配置的Bean后处理器将作用于当前配置文件中所有的Bean。

5.Bean生命周期之10步

在这里插入图片描述

6.Bean的作用域不同,管理方式不同

  • Spring 根据Bean的作用域来选择管理方式。
    • 对于singleton作用域的Bean,Spring 能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;
    • 而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
      * 对于 prototype 作用域Spring容器管理 Bean生命周期的前八步。

7.自己new的对象如何让Spring管理

  • 有些时候可能会遇到这样的需求,某个java对象是我们自己new的,然后我们希望这个对象被Spring容器管理,怎么实现?
package com.gdb.spring6.test;import com.gdb.spring6.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;public class RegisterBeanTest {@Testpublic void testBeanRegister(){// 自己new的对象User user = new User();System.out.println(user);// 创建 默认可列表BeanFactory 对象DefaultListableBeanFactory factory = new DefaultListableBeanFactory();// 注册Beanfactory.registerSingleton("userBean", user);// 从spring容器中获取beanUser userBean = factory.getBean("userBean", User.class);System.out.println(userBean);}
}

四、Bean的循环依赖问题

1.什么是Bean的循环依赖

  • A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你,你也依赖我。
    在这里插入图片描述

2.singleton下的set注入产生的循环依赖

  • 在singleton + setter模式注入的情况下,循环依赖是没有问题的。Spring可以解决这个问题。
    • 主要原因是:在这种模式下 Spring 对 Bean 的管理主要分为清晰的两个阶段:
      • 第一阶段:在Spring容器加载的时候,实例化Bean,只要其中任意一个Bean实例化之后,马上进行“曝光”【不等属性赋值曝光】。
      • 第二阶段:Bean“曝光”之后,再进行属性的赋值(调用set方法。)
    • 核心解决方案是:实例化对象和对象的属性赋值分为两个阶段来完成的。

3. prototype下的set注入产生的循环依赖

  • 当循环依赖的所有Bean的scope="prototype"的时候,产生的循环依赖,Spring是无法解决的,会出现BeanCurrentlyInCreationException异常。
  • 如果其中一个是singleton,另一个是prototype,是没有问题的。

4.singleton下的构造注入产生的循环依赖

  • 因为构造方法注入会导致实例化对象的过程和对象属性赋值的过程没有分离开,必须在一起完成导致的。

5.Spring解决循环依赖的机理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 总结:
    • Spring只能解决setter方法注入的单例bean之间的循环依赖。ClassA依赖ClassB,ClassB又依赖ClassA,形成依赖闭环。Spring在创建ClassA对象后,不需要等给属性赋值,直接将其曝光到bean缓存当中。在解析ClassA的属性时,又发现依赖于ClassB,再次去获取ClassB,当解析ClassB的属性时,又发现需要ClassA的属性,但此时的ClassA已经被提前曝光加入了正在创建的bean的缓存中,则无需创建新的的ClassA的实例,直接从缓存中获取即可。从而解决循环依赖问题。

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

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

相关文章

【大厂AI课学习笔记NO.60】(13)模型泛化性的评价

我们学习了过拟合和欠拟合&#xff0c;具体见我的文章&#xff1a;https://giszz.blog.csdn.net/article/details/136440338 那么今天&#xff0c;我们来学习模型泛化性的评价。 泛化性的问题&#xff0c;我们也讨论过了&#xff0c;那么如何评价模型的泛化性呢&#xff1f; …

激光SLAM技术助力富唯智能复合机器人的应用场景无限拓展

随着科技的不断进步&#xff0c;智能机器人已成为现代工业、服务、医疗等多个领域的重要角色。而在这一变革中&#xff0c;激光SLAM技术发挥着至关重要的作用。特别是对于富唯智能复合机器人来说&#xff0c;激光SLAM技术不仅提升了其智能化水平&#xff0c;更使其应用场景变得…

【促销定价】背后的算法技术3-数据挖掘分析

【促销定价】背后的算法技术3-数据挖掘分析 01 整体分析1&#xff09;整体概览2&#xff09;类别型特征概览3&#xff09;数值型特征概览 02 聚合分析1&#xff09;天维度2&#xff09;品维度3&#xff09;价格维度4&#xff09;数量维度 03 相关分析1&#xff09;1级品类2&…

无公网ip环境使用DS file软件远程访问内网群晖NAS中储存的文件

文章目录 1. 群晖安装Cpolar2. 创建TCP公网地址3. 远程访问群晖文件4. 固定TCP公网地址5. 固定TCP地址连接 DS file 是一个由群晖公司开发的文件管理应用程序&#xff0c;主要用于浏览、访问和管理存储在群晖NAS&#xff08;网络附加存储&#xff09;中的文件。这个应用程序具有…

echarts如何实现3D饼图(环形图)?

一、实现的效果 二、具体步骤 1.安装依赖 npm install echarts 2.引入echarts import * as echarts from echarts; 注意&#xff1a;这里需要用到echarts-gl&#xff0c;必须单独引入才可以 import echarts-gl; 3.echarts部分代码 我知道这部分内容很多&#xff0c;但只要cv…

羊大师揭秘羊奶与健康,美味的保健佳品

羊大师揭秘羊奶与健康&#xff0c;美味的保健佳品 羊奶确实是一种美味且健康的保健佳品&#xff0c;其独特的营养成分和风味使其成为许多人的健康选择。以下是一些羊奶与健康的关系&#xff1a; 营养丰富&#xff1a;羊奶含有丰富的蛋白质、脂肪、矿物质和维生素&#xff0c;…

ruoyi-nbcio-plus的Vue3前端升级组件后出现的问题(一)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a; http://122.227.135.243:9666 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbach…

大模型ChatGLM-6B实现本地部署

大模型ChatGLM-6B实现本地部署 一、写在前面&#xff1a;二、ChatGLM-6B下载&#xff1a;三、项目所需要的环境配置&#xff1a;四、项目运行&#xff1a;五、遇到的主要问题及解决 一、写在前面&#xff1a; 1、 确保你的电脑中已安装git&#xff0c;git lfs。 2、确保你的电…

浅析前端的堆栈原理以及深浅拷贝原理

浅析前端的堆栈原理以及深浅拷贝原理 首先来看一个案例 const obj {name:hzw,age:18 } let objName2 obj objName2.age 12 console.log(obj,objName2) // {name: hzw, age: 12} {name: hzw, age: 12}这里是不是很奇怪&#xff0c;为什么&#xff0c;为什么我改变objName2的…

AirPods Pro 2 耳机推送新固件,苹果Find My功能助力产品成长

苹果公司面向 AirPods Pro 2&#xff08;包括 USB-C 和 Lightning 版本&#xff09;&#xff0c;推出了全新的测试版固件更新&#xff0c;版本号为 6E188&#xff0c;高于 12 月份发布的 6B34 固件。 苹果和往常一样&#xff0c;并没有提供详细的更新日志或者说明&#xff0c…

算法刷题day20:二分

目录 引言概念一、借教室二、分巧克力三、管道四、技能升级五、冶炼金属六、数的范围七、最佳牛围栏 引言 这几天一直在做二分的题&#xff0c;都是上了难度的题目&#xff0c;本来以为自己的二分水平已经非常熟悉了&#xff0c;没想到还是糊涂了一两天才重新想清楚&#xff0…

力扣区间题:合并区间、插入区间

我们可以将区间按照左端点升序排列&#xff0c;然后遍历区间进行合并操作。 我们先将第一个区间加入答案&#xff0c;然后依次考虑之后的每个区间&#xff1a; 如果答案数组中最后一个区间的右端点小于当前考虑区间的左端点&#xff0c;说明两个区间不会重合&#xff0c;因此…

Java基于springboot的课程作业管理系统

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

Linux常见命令总结

1.创建文件夹 mkdir 目录名 mkdir 文件夹名 创建单个文件夹 mkdir 文件夹1 文件夹2 文件夹3 创建多个文件夹 mkdir -p parent/child 创建多级文件夹 2.创建文件 touch 文件名 touch的主要功能有两个,如果要创建的文件的名称存在,将文件的创建时间修改到当前的系统时间(也…

五种常用的可视化项目管理工具

传统的项目管理通常依赖于文本文档&#xff0c;容易造成误解和混乱。在快节奏的商业环境中&#xff0c;没有哪个项目经理愿意处理繁重的文档流程。 另一方面&#xff0c;可视化项目管理通常使用图表和视觉板来展示复杂的项目信息。因此&#xff0c;项目经理能快速了解关键信息…

基于 rk3566 的 uboot 分析 - dts 加载和 dm 模型的本质

文章目录 一、设备树加载使用1、概述2、第一阶段1) fdtdec_setup2) 总结 3、第二阶段1) kernle dtb 编译打包2) 加载流程2.1) board_init2.2) init_kernel_dtb2.3) rockchip_read_dtb_file2.4) rockchip_read_resource_dtb 3) 总结 二、dm 模型1、树的创建1) device_bind_commo…

使用Matlab计算IGRAv2探空站的Tm和PWV

1. 探空站IGRAv2数据 探空站的Tm常作为真值&#xff0c;去检验Tm线性公式或者ERA5 Tm等的精度 。 探空站PWV常作为真值&#xff0c;去检验GNSS PWV等的精度 2. Tm 的计算方法 Tm 的计算方法有两种在前面的文章有讲&#xff0c;这里用 使用水汽压和温度计算Tm。 ei和 Ti 表示…

本地如何配置支付宝模拟支付场景并结合内网穿透实现公网环境调试开发?

文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级子域名8. 测试使用固定二级子域名访问 前言 在沙箱环境调试支付SDK的时候&#xff0c;往往沙箱环境部署在本地&#xff0c;局限性大&#xff0c;在沙箱环境…

还在犹豫学不学?鸿蒙技术是否有前途的最强信号来了

2024年3月3日 上午10 点&#xff0c;深圳官方账号发布了一篇关于鸿蒙技术发展的重要文章&#xff0c;看到这篇文章后我非常激动&#xff0c;忍不住和大家分享一下&#xff01; 华为鸿蒙系统自提出以来&#xff0c;网友们的态度各不相同&#xff0c;有嘲笑“安卓套壳”的&#…

2024 CHINASHOP丨悠络客AI应用亮点抢鲜看,还有价值百元门票免费送哦!

3月13日-15日&#xff0c;备受国内外关注的第二十四届中国零售业博览会&#xff08;2024 CHINASHOP&#xff09;将在上海国家会展中心正式开展&#xff01;悠络客作为深耕智慧门店15年的公有云人工智能企业&#xff0c;也将带着全新AI产品和智慧门店解决方案亮相展会&#xff0…